mirror of
https://github.com/servalproject/serval-dna.git
synced 2025-01-29 15:43:56 +00:00
Refactor Rhizome result handling
- Introduce the new 'struct rhizome_bundle_result' that contains a rhizome_bundle_status enum value and an optional, nul-terminated string that provides an explanation of the cause of the status; add functions to construct, query, and free the struct - Replace 'enum rhizome_add_result' with 'struct rhizome_bundle_result', removing an unnecessary level of enum interpretation - Make rhizome_fill_manifest() return 'struct rhizome_bundle_result' and add logic to check that the supplied author SID is correct (previous behaviour was: if an incorrect author SID was supplied but the correct author could be found in the keyring, then the incorrect one was silently ignored) - Simplify the response code in rhizome_restful.cc to take advantage of the new 'struct rhizome_bundle_result'; in particular, the mapping from 'enum rhizome_bundle_status' codes to HTTP status codes is now expressed in a single switch statement - Fix some minor failures in test scripts revealed by the changes
This commit is contained in:
parent
078bf5eb6b
commit
98ed0406c5
3
httpd.c
3
httpd.c
@ -222,6 +222,7 @@ static void httpd_server_finalise_http_request(struct http_request *hr)
|
||||
if (current_httpd_requests == NULL) {
|
||||
assert(current_httpd_request_count == 0);
|
||||
}
|
||||
rhizome_bundle_result_free(&r->bundle_result);
|
||||
if (r->manifest) {
|
||||
rhizome_manifest_free(r->manifest);
|
||||
r->manifest = NULL;
|
||||
@ -273,7 +274,7 @@ void httpd_server_poll(struct sched_ent *alarm)
|
||||
current_httpd_requests = request;
|
||||
++current_httpd_request_count;
|
||||
request->payload_status = INVALID_RHIZOME_PAYLOAD_STATUS; // will cause FATAL unless set
|
||||
request->bundle_status = INVALID_RHIZOME_BUNDLE_STATUS; // will cause FATAL unless set
|
||||
request->bundle_result = INVALID_RHIZOME_BUNDLE_RESULT; // will cause FATAL unless set
|
||||
if (peerip)
|
||||
request->http.client_sockaddr_in = *peerip;
|
||||
request->http.uuid = http_request_uuid_counter;
|
||||
|
2
httpd.h
2
httpd.h
@ -61,7 +61,7 @@ typedef struct httpd_request
|
||||
*/
|
||||
rhizome_manifest *manifest;
|
||||
enum rhizome_payload_status payload_status;
|
||||
enum rhizome_bundle_status bundle_status;
|
||||
struct rhizome_bundle_result bundle_result;
|
||||
|
||||
/* For requests/responses that contain one or two SIDs.
|
||||
*/
|
||||
|
67
meshms.c
67
meshms.c
@ -69,8 +69,28 @@ static enum meshms_status get_my_conversation_bundle(const sid_t *my_sidp, rhizo
|
||||
if (m->haveSecret == NEW_BUNDLE_ID) {
|
||||
rhizome_manifest_set_service(m, RHIZOME_SERVICE_FILE);
|
||||
rhizome_manifest_set_name(m, "");
|
||||
if (rhizome_fill_manifest(m, NULL, my_sidp) != NULL)
|
||||
return WHY("Invalid conversation manifest");
|
||||
struct rhizome_bundle_result result = rhizome_fill_manifest(m, NULL, my_sidp);
|
||||
switch (result.status) {
|
||||
case RHIZOME_BUNDLE_STATUS_NEW:
|
||||
case RHIZOME_BUNDLE_STATUS_SAME:
|
||||
case RHIZOME_BUNDLE_STATUS_DUPLICATE:
|
||||
break;
|
||||
case RHIZOME_BUNDLE_STATUS_ERROR:
|
||||
case RHIZOME_BUNDLE_STATUS_INVALID:
|
||||
case RHIZOME_BUNDLE_STATUS_INCONSISTENT:
|
||||
WHYF("Error creating conversation manifest: %s", alloca_rhizome_bundle_result(result));
|
||||
return MESHMS_STATUS_ERROR;
|
||||
case RHIZOME_BUNDLE_STATUS_BUSY:
|
||||
// TODO
|
||||
case RHIZOME_BUNDLE_STATUS_OLD:
|
||||
case RHIZOME_BUNDLE_STATUS_FAKE:
|
||||
case RHIZOME_BUNDLE_STATUS_NO_ROOM:
|
||||
WARNF("Cannot create conversation manifest: %s", alloca_rhizome_bundle_result(result));
|
||||
return MESHMS_STATUS_PROTOCOL_FAULT;
|
||||
case RHIZOME_BUNDLE_STATUS_READONLY:
|
||||
INFOF("Cannot create conversation manifest: %s", alloca_rhizome_bundle_result(result));
|
||||
return MESHMS_STATUS_SID_LOCKED;
|
||||
}
|
||||
// The 'meshms' automated test depends on this message; do not alter.
|
||||
DEBUGF(meshms, "MESHMS CONVERSATION BUNDLE bid=%s secret=%s",
|
||||
alloca_tohex_rhizome_bid_t(m->cryptoSignPublic),
|
||||
@ -188,7 +208,7 @@ static enum meshms_status find_or_create_conv(const sid_t *my_sid, const sid_t *
|
||||
return status;
|
||||
}
|
||||
|
||||
static int create_ply(const sid_t *my_sid, struct meshms_conversations *conv, rhizome_manifest *m)
|
||||
static enum meshms_status create_ply(const sid_t *my_sid, struct meshms_conversations *conv, rhizome_manifest *m)
|
||||
{
|
||||
DEBUGF(meshms, "Creating ply for my_sid=%s them=%s",
|
||||
alloca_tohex_sid_t(conv->them),
|
||||
@ -199,8 +219,27 @@ static int create_ply(const sid_t *my_sid, struct meshms_conversations *conv, rh
|
||||
rhizome_manifest_set_recipient(m, &conv->them);
|
||||
rhizome_manifest_set_filesize(m, 0);
|
||||
rhizome_manifest_set_tail(m, 0);
|
||||
if (rhizome_fill_manifest(m, NULL, my_sid) != NULL)
|
||||
return -1;
|
||||
struct rhizome_bundle_result result = rhizome_fill_manifest(m, NULL, my_sid);
|
||||
switch (result.status) {
|
||||
case RHIZOME_BUNDLE_STATUS_NEW:
|
||||
case RHIZOME_BUNDLE_STATUS_SAME:
|
||||
case RHIZOME_BUNDLE_STATUS_DUPLICATE:
|
||||
break;
|
||||
case RHIZOME_BUNDLE_STATUS_ERROR:
|
||||
case RHIZOME_BUNDLE_STATUS_INVALID:
|
||||
case RHIZOME_BUNDLE_STATUS_INCONSISTENT:
|
||||
WHYF("Error creating ply manifest: %s", alloca_rhizome_bundle_result(result));
|
||||
return MESHMS_STATUS_ERROR;
|
||||
case RHIZOME_BUNDLE_STATUS_OLD:
|
||||
case RHIZOME_BUNDLE_STATUS_FAKE:
|
||||
case RHIZOME_BUNDLE_STATUS_NO_ROOM:
|
||||
case RHIZOME_BUNDLE_STATUS_BUSY:
|
||||
WARNF("Cannot create ply manifest: %s", alloca_rhizome_bundle_result(result));
|
||||
return MESHMS_STATUS_PROTOCOL_FAULT;
|
||||
case RHIZOME_BUNDLE_STATUS_READONLY:
|
||||
INFOF("Cannot create ply manifest: %s", alloca_rhizome_bundle_result(result));
|
||||
return MESHMS_STATUS_SID_LOCKED;
|
||||
}
|
||||
assert(m->haveSecret);
|
||||
assert(m->payloadEncryption == PAYLOAD_ENCRYPTED);
|
||||
conv->my_ply.bundle_id = m->cryptoSignPublic;
|
||||
@ -350,15 +389,25 @@ static enum meshms_status append_meshms_buffer(const sid_t *my_sid, struct meshm
|
||||
status = MESHMS_STATUS_PROTOCOL_FAULT;
|
||||
goto end;
|
||||
}
|
||||
} else if (create_ply(my_sid, conv, m) == -1) {
|
||||
goto end;
|
||||
} else {
|
||||
status = create_ply(my_sid, conv, m);
|
||||
switch (status) {
|
||||
case MESHMS_STATUS_OK:
|
||||
break;
|
||||
case MESHMS_STATUS_ERROR:
|
||||
case MESHMS_STATUS_UPDATED:
|
||||
case MESHMS_STATUS_SID_LOCKED:
|
||||
case MESHMS_STATUS_PROTOCOL_FAULT:
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
assert(m->haveSecret);
|
||||
assert(m->authorship == AUTHOR_AUTHENTIC);
|
||||
enum rhizome_payload_status pstatus = rhizome_append_journal_buffer(m, 0, buffer, len);
|
||||
if (pstatus != RHIZOME_PAYLOAD_STATUS_NEW)
|
||||
if (pstatus != RHIZOME_PAYLOAD_STATUS_NEW) {
|
||||
status = MESHMS_STATUS_ERROR;
|
||||
goto end;
|
||||
|
||||
}
|
||||
enum rhizome_bundle_status bstatus = rhizome_manifest_finalise(m, &mout, 1);
|
||||
DEBUGF(meshms, "bstatus=%d", bstatus);
|
||||
switch (bstatus) {
|
||||
|
295
rhizome.c
295
rhizome.c
@ -1,6 +1,6 @@
|
||||
/*
|
||||
Serval DNA - Rhizome entry points
|
||||
Copyright (C) 2012-2013 Serval Project Inc.
|
||||
Copyright (C) 2012-2015 Serval Project Inc.
|
||||
Copyright (C) 2011-2012 Paul Gardner-Stephen
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
@ -52,9 +52,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#include "serval.h"
|
||||
#include "conf.h"
|
||||
#include "str.h"
|
||||
#include "strbuf_helpers.h"
|
||||
#include "mem.h"
|
||||
#include "rhizome.h"
|
||||
#include "httpd.h"
|
||||
#include "dataformats.h"
|
||||
#include "log.h"
|
||||
#include "debug.h"
|
||||
|
||||
int is_rhizome_enabled()
|
||||
{
|
||||
@ -144,7 +148,7 @@ int rhizome_fetch_delay_ms()
|
||||
*
|
||||
* @author Andrew Bettison <andrew@servalproject.com>
|
||||
*/
|
||||
enum rhizome_add_file_result rhizome_manifest_add_file(int appending,
|
||||
struct rhizome_bundle_result rhizome_manifest_add_file(int appending,
|
||||
rhizome_manifest *m,
|
||||
rhizome_manifest **mout,
|
||||
const rhizome_bid_t *bid,
|
||||
@ -152,12 +156,9 @@ enum rhizome_add_file_result rhizome_manifest_add_file(int appending,
|
||||
const sid_t *author,
|
||||
const char *file_path,
|
||||
unsigned nassignments,
|
||||
const struct rhizome_manifest_field_assignment *assignments,
|
||||
strbuf reason
|
||||
)
|
||||
const struct rhizome_manifest_field_assignment *assignments)
|
||||
{
|
||||
const char *cause = NULL;
|
||||
enum rhizome_add_file_result result = RHIZOME_ADD_FILE_ERROR;
|
||||
struct rhizome_bundle_result result = INVALID_RHIZOME_BUNDLE_RESULT; // must be set before returning
|
||||
rhizome_manifest *existing_manifest = NULL;
|
||||
rhizome_manifest *new_manifest = NULL;
|
||||
assert(m != NULL);
|
||||
@ -167,25 +168,27 @@ enum rhizome_add_file_result rhizome_manifest_add_file(int appending,
|
||||
// If appending to a journal, caller must not supply 'version', 'filesize' or 'filehash' fields,
|
||||
// because these will be calculated by the journal append logic.
|
||||
if (appending) {
|
||||
if (m->version)
|
||||
DEBUG(rhizome, cause = "Cannot set 'version' field in journal append");
|
||||
else if (m->filesize != RHIZOME_SIZE_UNSET)
|
||||
DEBUG(rhizome, cause = "Cannot set 'filesize' field in journal append");
|
||||
else if (m->has_filehash)
|
||||
DEBUG(rhizome, cause = "Cannot set 'filehash' field in journal append");
|
||||
if (cause) {
|
||||
result = RHIZOME_ADD_FILE_INVALID_FOR_JOURNAL;
|
||||
if (m->version) {
|
||||
result = rhizome_bundle_result_static(RHIZOME_BUNDLE_STATUS_INVALID, "Cannot set 'version' field in journal append");
|
||||
goto error;
|
||||
}
|
||||
else if (m->filesize != RHIZOME_SIZE_UNSET) {
|
||||
result = rhizome_bundle_result_static(RHIZOME_BUNDLE_STATUS_INVALID, "Cannot set 'filesize' field in journal append");
|
||||
goto error;
|
||||
}
|
||||
else if (m->has_filehash) {
|
||||
result = rhizome_bundle_result_static(RHIZOME_BUNDLE_STATUS_INVALID, "Cannot set 'filehash' field in journal append");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
if (bid) {
|
||||
DEBUGF(rhizome, "Reading manifest from database: id=%s", alloca_tohex_rhizome_bid_t(*bid));
|
||||
if ((existing_manifest = rhizome_new_manifest()) == NULL) {
|
||||
WHY(cause = "Manifest struct could not be allocated");
|
||||
result = rhizome_bundle_result_static(RHIZOME_BUNDLE_STATUS_ERROR, "Manifest struct could not be allocated");
|
||||
goto error;
|
||||
}
|
||||
enum rhizome_bundle_status status = rhizome_retrieve_manifest(bid, existing_manifest);
|
||||
switch (status) {
|
||||
result.status = rhizome_retrieve_manifest(bid, existing_manifest);
|
||||
switch (result.status) {
|
||||
case RHIZOME_BUNDLE_STATUS_NEW:
|
||||
// No manifest with that bundle ID exists in the store, so we are building a bundle from
|
||||
// scratch.
|
||||
@ -204,18 +207,20 @@ enum rhizome_add_file_result rhizome_manifest_add_file(int appending,
|
||||
rhizome_manifest_del_filehash(existing_manifest);
|
||||
}
|
||||
if (rhizome_manifest_overwrite(existing_manifest, m) == -1) {
|
||||
WHY(cause = "Existing manifest could not be overwritten");
|
||||
result = rhizome_bundle_result_static(RHIZOME_BUNDLE_STATUS_ERROR,
|
||||
"Existing manifest could not be overwritten");
|
||||
goto error;
|
||||
}
|
||||
new_manifest = existing_manifest;
|
||||
existing_manifest = NULL;
|
||||
break;
|
||||
case RHIZOME_BUNDLE_STATUS_BUSY:
|
||||
WARN(cause = "Existing manifest not retrieved due to Rhizome store locking");
|
||||
result = RHIZOME_ADD_FILE_BUSY;
|
||||
result = rhizome_bundle_result_static(RHIZOME_BUNDLE_STATUS_BUSY,
|
||||
"Existing manifest not retrieved due to Rhizome store locking");
|
||||
goto error;
|
||||
case RHIZOME_BUNDLE_STATUS_ERROR:
|
||||
WHY(cause = "Error retrieving existing manifest from Rhizome store");
|
||||
result = rhizome_bundle_result_static(RHIZOME_BUNDLE_STATUS_BUSY,
|
||||
"Error retrieving existing manifest from Rhizome store");
|
||||
goto error;
|
||||
case RHIZOME_BUNDLE_STATUS_DUPLICATE:
|
||||
case RHIZOME_BUNDLE_STATUS_OLD:
|
||||
@ -224,7 +229,7 @@ enum rhizome_add_file_result rhizome_manifest_add_file(int appending,
|
||||
case RHIZOME_BUNDLE_STATUS_INCONSISTENT:
|
||||
case RHIZOME_BUNDLE_STATUS_NO_ROOM:
|
||||
case RHIZOME_BUNDLE_STATUS_READONLY:
|
||||
FATALF("rhizome_retrieve_manifest() returned %s", rhizome_bundle_status_message(status));
|
||||
FATALF("rhizome_retrieve_manifest() returned %s", rhizome_bundle_status_message(result.status));
|
||||
}
|
||||
}
|
||||
// If no existing bundle has been identified, we are building a bundle from scratch.
|
||||
@ -250,41 +255,37 @@ enum rhizome_add_file_result rhizome_manifest_add_file(int appending,
|
||||
enum rhizome_manifest_parse_status status = rhizome_manifest_parse_field(new_manifest, asg->label, asg->labellen, asg->value, asg->valuelen);
|
||||
int status_ok = 0;
|
||||
switch (status) {
|
||||
case RHIZOME_MANIFEST_ERROR:
|
||||
WHYF("Fatal error updating manifest field");
|
||||
if (reason)
|
||||
strbuf_sprintf(reason, "Fatal error updating manifest field: %s=%s", label, alloca_toprint(-1, asg->value, asg->valuelen));
|
||||
goto error;
|
||||
case RHIZOME_MANIFEST_OK:
|
||||
status_ok = 1;
|
||||
break;
|
||||
case RHIZOME_MANIFEST_SYNTAX_ERROR:
|
||||
DEBUGF(rhizome, "Manifest syntax error: %s=%s", label, alloca_toprint(-1, asg->value, asg->valuelen));
|
||||
if (reason)
|
||||
strbuf_sprintf(reason, "Manifest syntax error: %s=%s", label, alloca_toprint(-1, asg->value, asg->valuelen));
|
||||
result = RHIZOME_ADD_FILE_INVALID;
|
||||
goto error;
|
||||
case RHIZOME_MANIFEST_DUPLICATE_FIELD:
|
||||
// We already deleted the field, so if this happens, its a nasty bug
|
||||
FATALF("Duplicate field should not occur: %s=%s", label, alloca_toprint(-1, asg->value, asg->valuelen));
|
||||
case RHIZOME_MANIFEST_INVALID:
|
||||
DEBUGF(rhizome, "Manifest invalid field: %s=%s", label, alloca_toprint(-1, asg->value, asg->valuelen));
|
||||
if (reason)
|
||||
strbuf_sprintf(reason, "Manifest invalid field: %s=%s", label, alloca_toprint(-1, asg->value, asg->valuelen));
|
||||
result = RHIZOME_ADD_FILE_INVALID;
|
||||
goto error;
|
||||
case RHIZOME_MANIFEST_MALFORMED:
|
||||
DEBUGF(rhizome, "Manifest malformed field: %s=%s", label, alloca_toprint(-1, asg->value, asg->valuelen));
|
||||
if (reason)
|
||||
strbuf_sprintf(reason, "Manifest malformed field: %s=%s", label, alloca_toprint(-1, asg->value, asg->valuelen));
|
||||
result = RHIZOME_ADD_FILE_INVALID;
|
||||
goto error;
|
||||
case RHIZOME_MANIFEST_OVERFLOW:
|
||||
DEBUGF(rhizome, "Too many fields in manifest at: %s=%s", label, alloca_toprint(-1, asg->value, asg->valuelen));
|
||||
if (reason)
|
||||
strbuf_sprintf(reason, "Too many fields in manifest at: %s=%s", label, alloca_toprint(-1, asg->value, asg->valuelen));
|
||||
result = RHIZOME_ADD_FILE_INVALID;
|
||||
goto error;
|
||||
case RHIZOME_MANIFEST_ERROR:
|
||||
result = rhizome_bundle_result_sprintf(RHIZOME_BUNDLE_STATUS_ERROR,
|
||||
"Error updating manifest field: %s=%s",
|
||||
label, alloca_toprint(-1, asg->value, asg->valuelen));
|
||||
goto error;
|
||||
case RHIZOME_MANIFEST_OK:
|
||||
status_ok = 1;
|
||||
break;
|
||||
case RHIZOME_MANIFEST_SYNTAX_ERROR:
|
||||
result = rhizome_bundle_result_sprintf(RHIZOME_BUNDLE_STATUS_INVALID,
|
||||
"Manifest syntax error: %s=%s",
|
||||
label, alloca_toprint(-1, asg->value, asg->valuelen));
|
||||
goto error;
|
||||
case RHIZOME_MANIFEST_DUPLICATE_FIELD:
|
||||
// We already deleted the field, so if this happens, its a logic bug.
|
||||
FATALF("Duplicate field should not occur: %s=%s", label, alloca_toprint(-1, asg->value, asg->valuelen));
|
||||
case RHIZOME_MANIFEST_INVALID:
|
||||
result = rhizome_bundle_result_sprintf(RHIZOME_BUNDLE_STATUS_INVALID,
|
||||
"Manifest invalid field: %s=%s",
|
||||
label, alloca_toprint(-1, asg->value, asg->valuelen));
|
||||
goto error;
|
||||
case RHIZOME_MANIFEST_MALFORMED:
|
||||
result = rhizome_bundle_result_sprintf(RHIZOME_BUNDLE_STATUS_INVALID,
|
||||
"Manifest malformed field: %s=%s",
|
||||
label, alloca_toprint(-1, asg->value, asg->valuelen));
|
||||
goto error;
|
||||
case RHIZOME_MANIFEST_OVERFLOW:
|
||||
result = rhizome_bundle_result_sprintf(RHIZOME_BUNDLE_STATUS_INVALID,
|
||||
"Too many fields in manifest at: %s=%s",
|
||||
label, alloca_toprint(-1, asg->value, asg->valuelen));
|
||||
goto error;
|
||||
}
|
||||
if (!status_ok)
|
||||
FATALF("status = %d", status);
|
||||
@ -292,22 +293,20 @@ enum rhizome_add_file_result rhizome_manifest_add_file(int appending,
|
||||
}
|
||||
}
|
||||
if (appending && !new_manifest->is_journal) {
|
||||
cause = "Cannot append to a non-journal";
|
||||
DEBUG(rhizome, cause);
|
||||
result = RHIZOME_ADD_FILE_REQUIRES_JOURNAL;
|
||||
result = rhizome_bundle_result_static(RHIZOME_BUNDLE_STATUS_INVALID,
|
||||
"Cannot append to a non-journal");
|
||||
goto error;
|
||||
}
|
||||
if (!appending && new_manifest->is_journal) {
|
||||
cause = "Cannot add a journal bundle (use append instead)";
|
||||
DEBUG(rhizome, cause);
|
||||
result = RHIZOME_ADD_FILE_INVALID_FOR_JOURNAL;
|
||||
result = rhizome_bundle_result_static(RHIZOME_BUNDLE_STATUS_INVALID,
|
||||
"Cannot add a journal bundle (use append instead)");
|
||||
goto error;
|
||||
}
|
||||
if (bsk) {
|
||||
if (new_manifest->has_id) {
|
||||
if (!rhizome_apply_bundle_secret(new_manifest, bsk)) {
|
||||
WHY(cause = "Supplied bundle secret does not match Bundle Id");
|
||||
result = RHIZOME_ADD_FILE_WRONG_SECRET;
|
||||
result = rhizome_bundle_result_static(RHIZOME_BUNDLE_STATUS_READONLY,
|
||||
"Supplied bundle secret does not match Bundle Id");
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
@ -320,19 +319,29 @@ enum rhizome_add_file_result rhizome_manifest_add_file(int appending,
|
||||
WARNF("Manifest 'service' field not supplied - setting to '%s'", RHIZOME_SERVICE_FILE);
|
||||
rhizome_manifest_set_service(new_manifest, RHIZOME_SERVICE_FILE);
|
||||
}
|
||||
if ((cause = rhizome_fill_manifest(new_manifest, file_path, author ? author : NULL)) != NULL)
|
||||
goto error;
|
||||
*mout = new_manifest;
|
||||
return RHIZOME_ADD_FILE_OK;
|
||||
result = rhizome_fill_manifest(new_manifest, file_path, author);
|
||||
error:
|
||||
assert(result != RHIZOME_ADD_FILE_OK);
|
||||
if (cause && reason)
|
||||
strbuf_puts(reason, cause);
|
||||
if (new_manifest && new_manifest != m && new_manifest != existing_manifest)
|
||||
rhizome_manifest_free(new_manifest);
|
||||
if (existing_manifest)
|
||||
rhizome_manifest_free(existing_manifest);
|
||||
return result;
|
||||
switch (result.status) {
|
||||
case RHIZOME_BUNDLE_STATUS_NEW:
|
||||
*mout = new_manifest;
|
||||
return result;
|
||||
case RHIZOME_BUNDLE_STATUS_ERROR:
|
||||
case RHIZOME_BUNDLE_STATUS_SAME:
|
||||
case RHIZOME_BUNDLE_STATUS_DUPLICATE:
|
||||
case RHIZOME_BUNDLE_STATUS_OLD:
|
||||
case RHIZOME_BUNDLE_STATUS_INVALID:
|
||||
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_BUSY:
|
||||
if (new_manifest && new_manifest != m && new_manifest != existing_manifest)
|
||||
rhizome_manifest_free(new_manifest);
|
||||
if (existing_manifest)
|
||||
rhizome_manifest_free(existing_manifest);
|
||||
return result;
|
||||
}
|
||||
FATALF("result.status = %d", (int)result.status);
|
||||
}
|
||||
|
||||
/* Import a bundle from a pair of files, one containing the manifest and the optional other
|
||||
@ -648,3 +657,133 @@ const char *rhizome_payload_status_message_nonnull(enum rhizome_payload_status s
|
||||
const char *message = rhizome_payload_status_message(status);
|
||||
return message ? message : "Invalid";
|
||||
}
|
||||
|
||||
void rhizome_bundle_result_free(struct rhizome_bundle_result *resultp)
|
||||
{
|
||||
if (resultp->free) {
|
||||
resultp->free((void *)resultp->message);
|
||||
}
|
||||
*resultp = INVALID_RHIZOME_BUNDLE_RESULT;
|
||||
}
|
||||
|
||||
static const char *rhizome_bundle_status_symbol(enum rhizome_bundle_status status)
|
||||
{
|
||||
switch (status) {
|
||||
case RHIZOME_BUNDLE_STATUS_NEW: return "NEW";
|
||||
case RHIZOME_BUNDLE_STATUS_SAME: return "SAME";
|
||||
case RHIZOME_BUNDLE_STATUS_DUPLICATE: return "DUPLICATE";
|
||||
case RHIZOME_BUNDLE_STATUS_OLD: return "OLD";
|
||||
case RHIZOME_BUNDLE_STATUS_INVALID: return "INVALID";
|
||||
case RHIZOME_BUNDLE_STATUS_FAKE: return "FAKE";
|
||||
case RHIZOME_BUNDLE_STATUS_INCONSISTENT: return "INCONSISTENT";
|
||||
case RHIZOME_BUNDLE_STATUS_NO_ROOM: return "NO_ROOM";
|
||||
case RHIZOME_BUNDLE_STATUS_READONLY: return "READONLY";
|
||||
case RHIZOME_BUNDLE_STATUS_BUSY: return "BUSY";
|
||||
case RHIZOME_BUNDLE_STATUS_ERROR: return "ERROR";
|
||||
}
|
||||
FATALF("status=%d", (int)status);
|
||||
}
|
||||
|
||||
static void log_rhizome_bundle_result(struct __sourceloc __whence, struct rhizome_bundle_result result)
|
||||
{
|
||||
switch (result.status) {
|
||||
case RHIZOME_BUNDLE_STATUS_NEW:
|
||||
case RHIZOME_BUNDLE_STATUS_SAME:
|
||||
case RHIZOME_BUNDLE_STATUS_DUPLICATE:
|
||||
case RHIZOME_BUNDLE_STATUS_OLD:
|
||||
case RHIZOME_BUNDLE_STATUS_INVALID:
|
||||
case RHIZOME_BUNDLE_STATUS_FAKE:
|
||||
case RHIZOME_BUNDLE_STATUS_INCONSISTENT:
|
||||
case RHIZOME_BUNDLE_STATUS_NO_ROOM:
|
||||
case RHIZOME_BUNDLE_STATUS_READONLY:
|
||||
DEBUG(rhizome, alloca_rhizome_bundle_result(result));
|
||||
return;
|
||||
case RHIZOME_BUNDLE_STATUS_BUSY:
|
||||
WARN(alloca_rhizome_bundle_result(result));
|
||||
return;
|
||||
case RHIZOME_BUNDLE_STATUS_ERROR:
|
||||
WHY(alloca_rhizome_bundle_result(result));
|
||||
return;
|
||||
}
|
||||
FATAL(alloca_rhizome_bundle_result(result));
|
||||
}
|
||||
|
||||
|
||||
struct rhizome_bundle_result _rhizome_bundle_result(struct __sourceloc __whence, enum rhizome_bundle_status status)
|
||||
{
|
||||
struct rhizome_bundle_result result = INVALID_RHIZOME_BUNDLE_RESULT;
|
||||
result.status = status;
|
||||
log_rhizome_bundle_result(__whence, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
struct rhizome_bundle_result _rhizome_bundle_result_static(struct __sourceloc __whence, enum rhizome_bundle_status status, const char *message)
|
||||
{
|
||||
struct rhizome_bundle_result result = INVALID_RHIZOME_BUNDLE_RESULT;
|
||||
result.status = status;
|
||||
result.message = message;
|
||||
log_rhizome_bundle_result(__whence, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
struct rhizome_bundle_result _rhizome_bundle_result_strdup(struct __sourceloc __whence, enum rhizome_bundle_status status, const char *message)
|
||||
{
|
||||
assert(message != NULL);
|
||||
struct rhizome_bundle_result result = INVALID_RHIZOME_BUNDLE_RESULT;
|
||||
result.status = status;
|
||||
result.message = str_edup(message);
|
||||
result.free = free;
|
||||
log_rhizome_bundle_result(__whence, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
struct rhizome_bundle_result _rhizome_bundle_result_sprintf(struct __sourceloc __whence, enum rhizome_bundle_status status, const char *fmt, ...)
|
||||
{
|
||||
struct rhizome_bundle_result result = INVALID_RHIZOME_BUNDLE_RESULT;
|
||||
result.status = status;
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
strbuf sb;
|
||||
STRBUF_ALLOCA_FIT(sb, 200, (strbuf_vsprintf(sb, fmt, ap)));
|
||||
va_end(ap);
|
||||
result.message = str_edup(strbuf_str(sb));
|
||||
result.free = free;
|
||||
log_rhizome_bundle_result(__whence, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
const char *rhizome_bundle_result_message(struct rhizome_bundle_result result)
|
||||
{
|
||||
return result.message ? result.message : rhizome_bundle_status_message(result.status);
|
||||
}
|
||||
|
||||
const char *rhizome_bundle_result_message_nonnull(struct rhizome_bundle_result result)
|
||||
{
|
||||
return result.message ? result.message : rhizome_bundle_status_message_nonnull(result.status);
|
||||
}
|
||||
|
||||
strbuf strbuf_append_rhizome_bundle_result(strbuf sb, struct rhizome_bundle_result result)
|
||||
{
|
||||
switch (result.status) {
|
||||
case RHIZOME_BUNDLE_STATUS_NEW:
|
||||
case RHIZOME_BUNDLE_STATUS_SAME:
|
||||
case RHIZOME_BUNDLE_STATUS_DUPLICATE:
|
||||
case RHIZOME_BUNDLE_STATUS_OLD:
|
||||
case RHIZOME_BUNDLE_STATUS_INVALID:
|
||||
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_BUSY:
|
||||
case RHIZOME_BUNDLE_STATUS_ERROR:
|
||||
strbuf_puts(sb, "RHIZOME_BUNDLE_STATUS_");
|
||||
strbuf_puts(sb, rhizome_bundle_status_symbol(result.status));
|
||||
if (result.message) {
|
||||
strbuf_puts(sb, " ");
|
||||
strbuf_toprint_quoted(sb, "``", result.message);
|
||||
}
|
||||
return sb;
|
||||
}
|
||||
strbuf_sprintf(sb, "Invalid rhizome_bundle_status (%d)", (int)result.status);
|
||||
return sb;
|
||||
}
|
||||
|
65
rhizome.h
65
rhizome.h
@ -421,6 +421,40 @@ enum rhizome_bundle_status {
|
||||
const char *rhizome_bundle_status_message(enum rhizome_bundle_status);
|
||||
const char *rhizome_bundle_status_message_nonnull(enum rhizome_bundle_status);
|
||||
|
||||
// Encapsulate a status enum value and an optional text message to assist with
|
||||
// diagnostics. Useful as a return value from functions that can fail in all
|
||||
// sorts of ways.
|
||||
struct rhizome_bundle_result {
|
||||
enum rhizome_bundle_status status;
|
||||
const char *message;
|
||||
void (*free)(void *); // call r.free(r.message) before destroying r
|
||||
};
|
||||
|
||||
#define INVALID_RHIZOME_BUNDLE_RESULT ((struct rhizome_bundle_result){ .status = INVALID_RHIZOME_BUNDLE_STATUS, .message = NULL, .free = NULL })
|
||||
|
||||
// Call this before discarding a struct rhizome_bundle_result.
|
||||
void rhizome_bundle_result_free(struct rhizome_bundle_result *);
|
||||
|
||||
// Convenience functions for constructing a struct rhizome_bundle_result and
|
||||
// logging errors and debug messages in the process.
|
||||
struct rhizome_bundle_result _rhizome_bundle_result(struct __sourceloc, enum rhizome_bundle_status);
|
||||
struct rhizome_bundle_result _rhizome_bundle_result_static(struct __sourceloc, enum rhizome_bundle_status, const char *);
|
||||
struct rhizome_bundle_result _rhizome_bundle_result_strdup(struct __sourceloc, enum rhizome_bundle_status, const char *);
|
||||
struct rhizome_bundle_result _rhizome_bundle_result_sprintf(struct __sourceloc, enum rhizome_bundle_status, const char *fmt, ...);
|
||||
|
||||
#define rhizome_bundle_result(status) _rhizome_bundle_result(__WHENCE__, status)
|
||||
#define rhizome_bundle_result_static(status, str) _rhizome_bundle_result_static(__WHENCE__, status, str);
|
||||
#define rhizome_bundle_result_strdup(status, str) _rhizome_bundle_result_strdup(__WHENCE__, status, str);
|
||||
#define rhizome_bundle_result_sprintf(status, fmt, ...) _rhizome_bundle_result_sprintf(__WHENCE__, status, fmt, ## __VA_ARGS__);
|
||||
|
||||
// Functions for extracting information from a struct rhizome_bundle_result.
|
||||
const char *rhizome_bundle_result_message(struct rhizome_bundle_result); // NULL only if invalid
|
||||
const char *rhizome_bundle_result_message_nonnull(struct rhizome_bundle_result);
|
||||
|
||||
// Function to assist logging struct rhizome_bundle_result.
|
||||
#define alloca_rhizome_bundle_result(result) strbuf_str(strbuf_append_rhizome_bundle_result(strbuf_alloca(50 + (result.message ? strlen(result.message) : 0)), result))
|
||||
strbuf strbuf_append_rhizome_bundle_result(strbuf, struct rhizome_bundle_result);
|
||||
|
||||
enum rhizome_payload_status {
|
||||
RHIZOME_PAYLOAD_STATUS_ERROR = -1,
|
||||
RHIZOME_PAYLOAD_STATUS_EMPTY = 0, // payload is empty (zero length)
|
||||
@ -458,30 +492,19 @@ rhizome_manifest *_rhizome_new_manifest(struct __sourceloc);
|
||||
int rhizome_store_manifest(rhizome_manifest *m);
|
||||
int rhizome_store_file(rhizome_manifest *m,const unsigned char *key);
|
||||
|
||||
enum rhizome_add_file_result {
|
||||
RHIZOME_ADD_FILE_ERROR = -1,
|
||||
RHIZOME_ADD_FILE_OK = 0, // manifest created successfully
|
||||
RHIZOME_ADD_FILE_INVALID, // manifest not created due to invalid input
|
||||
RHIZOME_ADD_FILE_BUSY, // manifest not created because database busy
|
||||
RHIZOME_ADD_FILE_REQUIRES_JOURNAL, // operation is only valid for a journal
|
||||
RHIZOME_ADD_FILE_INVALID_FOR_JOURNAL, // operation is not valid for a journal
|
||||
RHIZOME_ADD_FILE_WRONG_SECRET, // incorrect bundle secret supplied
|
||||
};
|
||||
enum rhizome_add_file_result rhizome_manifest_add_file(int appending,
|
||||
rhizome_manifest *m,
|
||||
rhizome_manifest **mout,
|
||||
const rhizome_bid_t *bid,
|
||||
const rhizome_bk_t *bsk,
|
||||
const sid_t *author,
|
||||
const char *file_path,
|
||||
unsigned nassignments,
|
||||
const struct rhizome_manifest_field_assignment *assignments,
|
||||
strbuf reason
|
||||
);
|
||||
struct rhizome_bundle_result rhizome_manifest_add_file(int appending,
|
||||
rhizome_manifest *m,
|
||||
rhizome_manifest **mout,
|
||||
const rhizome_bid_t *bid,
|
||||
const rhizome_bk_t *bsk,
|
||||
const sid_t *author,
|
||||
const char *file_path,
|
||||
unsigned nassignments,
|
||||
const struct rhizome_manifest_field_assignment *assignments);
|
||||
int rhizome_bundle_import_files(rhizome_manifest *m, rhizome_manifest **m_out, const char *manifest_path, const char *filepath);
|
||||
|
||||
int rhizome_manifest_set_name_from_path(rhizome_manifest *m, const char *filepath);
|
||||
const char * rhizome_fill_manifest(rhizome_manifest *m, const char *filepath, const sid_t *authorSidp);
|
||||
struct rhizome_bundle_result rhizome_fill_manifest(rhizome_manifest *m, const char *filepath, const sid_t *authorSidp);
|
||||
|
||||
int rhizome_apply_bundle_secret(rhizome_manifest *, const rhizome_bk_t *);
|
||||
int rhizome_manifest_add_bundle_key(rhizome_manifest *);
|
||||
|
@ -1480,13 +1480,13 @@ int rhizome_manifest_set_name_from_path(rhizome_manifest *m, const char *filepat
|
||||
* - create an ID if there is none, otherwise authenticate the existing one
|
||||
* - if service is file, then use the payload file's basename for "name"
|
||||
*
|
||||
* Return NULL if successful, otherwise a pointer to a static text string describing the reason for
|
||||
* the failure (always an internal/unrecoverable error).
|
||||
* Return a rhizome_bundle_status code together with a pointer to a text string describing the
|
||||
* reason for the failure (always an internal/unrecoverable error). The string is accompanied by a
|
||||
* pointer to a "free" method (eg, free(3)) that must be called to release the string before the
|
||||
* pointer is discarded.
|
||||
*/
|
||||
const char * rhizome_fill_manifest(rhizome_manifest *m, const char *filepath, const sid_t *authorSidp)
|
||||
struct rhizome_bundle_result rhizome_fill_manifest(rhizome_manifest *m, const char *filepath, const sid_t *authorSidp)
|
||||
{
|
||||
const char *reason = NULL;
|
||||
|
||||
/* Set version of manifest from current time if not already set. */
|
||||
if (m->version == 0)
|
||||
rhizome_manifest_set_version(m, gettime_ms());
|
||||
@ -1513,8 +1513,7 @@ const char * rhizome_fill_manifest(rhizome_manifest *m, const char *filepath, co
|
||||
// If there is no Bundle Id, then create a new bundle Id and secret from scratch.
|
||||
DEBUG(rhizome, "creating new bundle");
|
||||
if (rhizome_manifest_createid(m) == -1) {
|
||||
WHY(reason = "Could not bind manifest to an ID");
|
||||
return reason;
|
||||
return rhizome_bundle_result_static(RHIZOME_BUNDLE_STATUS_ERROR, "Could not bind manifest to an ID");
|
||||
}
|
||||
// fall through to set the BK field...
|
||||
case NEW_BUNDLE_ID:
|
||||
@ -1540,12 +1539,32 @@ const char * rhizome_fill_manifest(rhizome_manifest *m, const char *filepath, co
|
||||
}
|
||||
if (!valid_haveSecret)
|
||||
FATALF("haveSecret = %d", m->haveSecret);
|
||||
int valid_authorship = 0;
|
||||
switch (m->authorship) {
|
||||
case ANONYMOUS:
|
||||
assert(!authorSidp);
|
||||
valid_authorship = 1;
|
||||
break;
|
||||
case AUTHOR_AUTHENTIC:
|
||||
valid_authorship = 1;
|
||||
break;
|
||||
case AUTHOR_UNKNOWN:
|
||||
return rhizome_bundle_result_static(RHIZOME_BUNDLE_STATUS_READONLY, "Author is not in keyring");
|
||||
case AUTHOR_IMPOSTOR:
|
||||
return rhizome_bundle_result_static(RHIZOME_BUNDLE_STATUS_READONLY, "Incorrect author");
|
||||
case AUTHOR_NOT_CHECKED:
|
||||
case AUTHOR_LOCAL:
|
||||
FATALF("logic error (bug): m->authorship = %d", m->authorship);
|
||||
case AUTHENTICATION_ERROR:
|
||||
return rhizome_bundle_result_static(RHIZOME_BUNDLE_STATUS_ERROR, "Error authenticating author");
|
||||
}
|
||||
if (!valid_authorship)
|
||||
FATALF("m->authorship = %d", (int)m->authorship);
|
||||
|
||||
/* Service field must already be set.
|
||||
*/
|
||||
if (m->service == NULL) {
|
||||
WHYF(reason = "Missing 'service' field");
|
||||
return reason;
|
||||
return rhizome_bundle_result_static(RHIZOME_BUNDLE_STATUS_INVALID, "Missing 'service' field");
|
||||
}
|
||||
DEBUGF(rhizome, "manifest contains service=%s", m->service);
|
||||
|
||||
@ -1579,7 +1598,7 @@ const char * rhizome_fill_manifest(rhizome_manifest *m, const char *filepath, co
|
||||
rhizome_manifest_set_crypt(m, PAYLOAD_ENCRYPTED);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return rhizome_bundle_result(RHIZOME_BUNDLE_STATUS_NEW);
|
||||
}
|
||||
|
||||
/* Work out the authorship status of the bundle without performing any cryptographic checks.
|
||||
|
@ -180,6 +180,7 @@ static int app_rhizome_add_file(const struct cli_parsed *parsed, struct cli_cont
|
||||
|
||||
int ret = -1;
|
||||
rhizome_manifest *m = NULL;
|
||||
struct rhizome_bundle_result result = INVALID_RHIZOME_BUNDLE_RESULT;
|
||||
if (rhizome_opendb() == -1)
|
||||
goto finish;
|
||||
|
||||
@ -205,39 +206,16 @@ static int app_rhizome_add_file(const struct cli_parsed *parsed, struct cli_cont
|
||||
/* Create an in-memory manifest for the file being added.
|
||||
*/
|
||||
rhizome_manifest *mout = NULL;
|
||||
enum rhizome_add_file_result result = rhizome_manifest_add_file(appending, m, &mout,
|
||||
bundleIdHex ? &bid : NULL,
|
||||
bsktext ? &bsk : NULL,
|
||||
authorSidHex ? &authorSid : NULL,
|
||||
filepath,
|
||||
nfields, fields,
|
||||
NULL);
|
||||
int result_valid = 0;
|
||||
switch (result) {
|
||||
case RHIZOME_ADD_FILE_ERROR:
|
||||
ret = -1;
|
||||
goto finish;
|
||||
case RHIZOME_ADD_FILE_OK:
|
||||
result_valid = 1;
|
||||
break;
|
||||
case RHIZOME_ADD_FILE_INVALID:
|
||||
ret = RHIZOME_BUNDLE_STATUS_INVALID; // TODO separate enum for CLI return codes
|
||||
goto finish;
|
||||
case RHIZOME_ADD_FILE_BUSY:
|
||||
ret = RHIZOME_BUNDLE_STATUS_BUSY; // TODO separate enum for CLI return codes
|
||||
goto finish;
|
||||
case RHIZOME_ADD_FILE_REQUIRES_JOURNAL:
|
||||
ret = RHIZOME_BUNDLE_STATUS_INVALID; // TODO separate enum for CLI return codes
|
||||
goto finish;
|
||||
case RHIZOME_ADD_FILE_INVALID_FOR_JOURNAL:
|
||||
ret = RHIZOME_BUNDLE_STATUS_INVALID; // TODO separate enum for CLI return codes
|
||||
goto finish;
|
||||
case RHIZOME_ADD_FILE_WRONG_SECRET:
|
||||
ret = RHIZOME_BUNDLE_STATUS_READONLY; // TODO separate enum for CLI return codes
|
||||
result = rhizome_manifest_add_file(appending, m, &mout,
|
||||
bundleIdHex ? &bid : NULL,
|
||||
bsktext ? &bsk : NULL,
|
||||
authorSidHex ? &authorSid : NULL,
|
||||
filepath,
|
||||
nfields, fields);
|
||||
if (result.status != RHIZOME_BUNDLE_STATUS_NEW) {
|
||||
ret = result.status; // TODO separate enum for CLI return codes
|
||||
goto finish;
|
||||
}
|
||||
if (!result_valid)
|
||||
FATALF("result = %d", result);
|
||||
assert(mout != NULL);
|
||||
if (mout != m) {
|
||||
rhizome_manifest_free(m);
|
||||
@ -260,50 +238,50 @@ static int app_rhizome_add_file(const struct cli_parsed *parsed, struct cli_cont
|
||||
DEBUGF(rhizome, "rhizome_store_payload_file() returned %d %s", pstatus, rhizome_payload_status_message(pstatus));
|
||||
}
|
||||
}
|
||||
enum rhizome_bundle_status status = RHIZOME_BUNDLE_STATUS_ERROR;
|
||||
rhizome_bundle_result_free(&result);
|
||||
int pstatus_valid = 0;
|
||||
switch (pstatus) {
|
||||
case RHIZOME_PAYLOAD_STATUS_EMPTY:
|
||||
case RHIZOME_PAYLOAD_STATUS_STORED:
|
||||
case RHIZOME_PAYLOAD_STATUS_NEW:
|
||||
pstatus_valid = 1;
|
||||
status = RHIZOME_BUNDLE_STATUS_NEW;
|
||||
result.status = RHIZOME_BUNDLE_STATUS_NEW;
|
||||
break;
|
||||
case RHIZOME_PAYLOAD_STATUS_TOO_BIG:
|
||||
case RHIZOME_PAYLOAD_STATUS_EVICTED:
|
||||
pstatus_valid = 1;
|
||||
status = RHIZOME_BUNDLE_STATUS_NO_ROOM;
|
||||
result.status = RHIZOME_BUNDLE_STATUS_NO_ROOM;
|
||||
INFO("Insufficient space to store payload");
|
||||
break;
|
||||
case RHIZOME_PAYLOAD_STATUS_ERROR:
|
||||
pstatus_valid = 1;
|
||||
status = RHIZOME_BUNDLE_STATUS_ERROR;
|
||||
result.status = RHIZOME_BUNDLE_STATUS_ERROR;
|
||||
break;
|
||||
case RHIZOME_PAYLOAD_STATUS_WRONG_SIZE:
|
||||
case RHIZOME_PAYLOAD_STATUS_WRONG_HASH:
|
||||
pstatus_valid = 1;
|
||||
status = RHIZOME_BUNDLE_STATUS_INCONSISTENT;
|
||||
result.status = RHIZOME_BUNDLE_STATUS_INCONSISTENT;
|
||||
break;
|
||||
case RHIZOME_PAYLOAD_STATUS_CRYPTO_FAIL:
|
||||
pstatus_valid = 1;
|
||||
status = RHIZOME_BUNDLE_STATUS_READONLY;
|
||||
result.status = RHIZOME_BUNDLE_STATUS_READONLY;
|
||||
break;
|
||||
}
|
||||
if (!pstatus_valid)
|
||||
FATALF("pstatus = %d", pstatus);
|
||||
if (status == RHIZOME_BUNDLE_STATUS_NEW) {
|
||||
if (result.status == RHIZOME_BUNDLE_STATUS_NEW) {
|
||||
if (!rhizome_manifest_validate(m) || m->malformed)
|
||||
status = RHIZOME_BUNDLE_STATUS_INVALID;
|
||||
result.status = RHIZOME_BUNDLE_STATUS_INVALID;
|
||||
else {
|
||||
status = rhizome_manifest_finalise(m, &mout, !force_new);
|
||||
result.status = rhizome_manifest_finalise(m, &mout, !force_new);
|
||||
if (mout && mout != m && !rhizome_manifest_validate(mout)) {
|
||||
WHYF("Stored manifest id=%s is invalid -- overwriting", alloca_tohex_rhizome_bid_t(mout->cryptoSignPublic));
|
||||
status = RHIZOME_BUNDLE_STATUS_NEW;
|
||||
result.status = RHIZOME_BUNDLE_STATUS_NEW;
|
||||
}
|
||||
}
|
||||
}
|
||||
int status_valid = 0;
|
||||
switch (status) {
|
||||
switch (result.status) {
|
||||
case RHIZOME_BUNDLE_STATUS_NEW:
|
||||
if (mout && mout != m)
|
||||
rhizome_manifest_free(mout);
|
||||
@ -334,11 +312,12 @@ static int app_rhizome_add_file(const struct cli_parsed *parsed, struct cli_cont
|
||||
// a valuable tool for the developer.
|
||||
}
|
||||
if (!status_valid)
|
||||
FATALF("status=%d", status);
|
||||
FATALF("result.status=%d", result.status);
|
||||
if (mout && mout != m)
|
||||
rhizome_manifest_free(mout);
|
||||
ret = status;
|
||||
ret = result.status;
|
||||
finish:
|
||||
rhizome_bundle_result_free(&result);
|
||||
rhizome_manifest_free(m);
|
||||
keyring_free(keyring);
|
||||
keyring = NULL;
|
||||
|
@ -243,10 +243,6 @@ void rhizome_authenticate_author(rhizome_manifest *m)
|
||||
{
|
||||
IN();
|
||||
DEBUGF(rhizome, "authenticate author for bid=%s", m->has_id ? alloca_tohex_rhizome_bid_t(m->cryptoSignPublic) : "(none)");
|
||||
if (!m->has_bundle_key) {
|
||||
DEBUG(rhizome, " no BK field");
|
||||
RETURNVOID;
|
||||
}
|
||||
switch (m->authorship) {
|
||||
case ANONYMOUS:
|
||||
DEBUGF(rhizome, " manifest[%d] author unknown", m->manifest_record_number);
|
||||
|
@ -248,13 +248,15 @@ static int rhizome_direct_addfile_end(struct http_request *hr)
|
||||
if (m->service == NULL)
|
||||
rhizome_manifest_set_service(m, RHIZOME_SERVICE_FILE);
|
||||
const sid_t *author = is_sid_t_any(config.rhizome.api.addfile.default_author) ? NULL : &config.rhizome.api.addfile.default_author;
|
||||
const char *reason = rhizome_fill_manifest(m, r->u.direct_import.data_file_name, author);
|
||||
if (reason) {
|
||||
struct rhizome_bundle_result result = rhizome_fill_manifest(m, r->u.direct_import.data_file_name, author);
|
||||
if (result.status != RHIZOME_BUNDLE_STATUS_NEW) {
|
||||
rhizome_manifest_free(m);
|
||||
rhizome_direct_clear_temporary_files(r);
|
||||
http_request_simple_response(&r->http, 500, alloca_sprintf(-1, "Internal Error: %s", reason));
|
||||
http_request_simple_response(&r->http, 500, result.message);
|
||||
rhizome_bundle_result_free(&result);
|
||||
return 0;
|
||||
}
|
||||
rhizome_bundle_result_free(&result);
|
||||
rhizome_manifest_set_crypt(m, PAYLOAD_CLEAR);
|
||||
// import file contents
|
||||
// TODO, stream file into database
|
||||
|
@ -70,96 +70,98 @@ 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)
|
||||
static int http_request_rhizome_response(struct httpd_request *r, uint16_t http_status, const char *http_reason)
|
||||
{
|
||||
uint16_t rhizome_result = 0;
|
||||
switch (r->bundle_status) {
|
||||
uint16_t rhizome_http_status = 0;
|
||||
switch (r->bundle_result.status) {
|
||||
case RHIZOME_BUNDLE_STATUS_SAME:
|
||||
case RHIZOME_BUNDLE_STATUS_DUPLICATE:
|
||||
rhizome_result = 200; // OK
|
||||
rhizome_http_status = 200; // OK
|
||||
break;
|
||||
case RHIZOME_BUNDLE_STATUS_NEW:
|
||||
rhizome_result = 201; // Created
|
||||
rhizome_http_status = 201; // Created
|
||||
break;
|
||||
case RHIZOME_BUNDLE_STATUS_NO_ROOM:
|
||||
case RHIZOME_BUNDLE_STATUS_OLD:
|
||||
rhizome_result = 202; // Accepted
|
||||
rhizome_http_status = 202; // Accepted
|
||||
break;
|
||||
case RHIZOME_BUNDLE_STATUS_FAKE:
|
||||
case RHIZOME_BUNDLE_STATUS_READONLY:
|
||||
rhizome_result = 419; // Authentication Timeout
|
||||
rhizome_http_status = 419; // Authentication Timeout
|
||||
break;
|
||||
case RHIZOME_BUNDLE_STATUS_INVALID:
|
||||
case RHIZOME_BUNDLE_STATUS_INCONSISTENT:
|
||||
rhizome_result = 422; // Unprocessable Entity
|
||||
rhizome_http_status = 422; // Unprocessable Entity
|
||||
break;
|
||||
case RHIZOME_BUNDLE_STATUS_BUSY:
|
||||
rhizome_result = 423; // Locked
|
||||
rhizome_http_status = 423; // Locked
|
||||
break;
|
||||
case RHIZOME_BUNDLE_STATUS_ERROR:
|
||||
rhizome_result = 500;
|
||||
rhizome_http_status = 500;
|
||||
break;
|
||||
}
|
||||
if (rhizome_result) {
|
||||
if (rhizome_http_status) {
|
||||
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);
|
||||
r->http.response.result_extra[0].value.u.integer = r->bundle_result.status;
|
||||
const char *status_message = rhizome_bundle_result_message(r->bundle_result);
|
||||
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;
|
||||
if (rhizome_http_status > http_status) {
|
||||
http_status = rhizome_http_status;
|
||||
if (!http_reason)
|
||||
http_reason = status_message;
|
||||
}
|
||||
}
|
||||
rhizome_result = 0;
|
||||
rhizome_http_status = 0;
|
||||
switch (r->payload_status) {
|
||||
case RHIZOME_PAYLOAD_STATUS_STORED:
|
||||
case RHIZOME_PAYLOAD_STATUS_EMPTY:
|
||||
rhizome_result = 200;
|
||||
rhizome_http_status = 200;
|
||||
break;
|
||||
case RHIZOME_PAYLOAD_STATUS_NEW:
|
||||
rhizome_result = 201;
|
||||
rhizome_http_status = 201;
|
||||
break;
|
||||
case RHIZOME_PAYLOAD_STATUS_TOO_BIG:
|
||||
case RHIZOME_PAYLOAD_STATUS_EVICTED:
|
||||
rhizome_result = 202; // Accepted
|
||||
rhizome_http_status = 202; // Accepted
|
||||
break;
|
||||
case RHIZOME_PAYLOAD_STATUS_CRYPTO_FAIL:
|
||||
rhizome_result = 419; // Authentication Timeout
|
||||
rhizome_http_status = 419; // Authentication Timeout
|
||||
break;
|
||||
case RHIZOME_PAYLOAD_STATUS_WRONG_SIZE:
|
||||
case RHIZOME_PAYLOAD_STATUS_WRONG_HASH:
|
||||
rhizome_result = 422; // Unprocessable Entity
|
||||
rhizome_http_status = 422; // Unprocessable Entity
|
||||
break;
|
||||
case RHIZOME_PAYLOAD_STATUS_ERROR:
|
||||
rhizome_result = 500;
|
||||
rhizome_http_status = 500;
|
||||
break;
|
||||
}
|
||||
if (rhizome_result) {
|
||||
if (rhizome_http_status) {
|
||||
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);
|
||||
const char *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 (rhizome_http_status > http_status) {
|
||||
http_status = rhizome_http_status;
|
||||
if (!http_reason)
|
||||
http_reason = status_message;
|
||||
}
|
||||
}
|
||||
if (result == 0) {
|
||||
result = 500;
|
||||
message = "Result logic error";
|
||||
if (http_status == 0) {
|
||||
http_status = 500;
|
||||
http_reason = "Invalid result";
|
||||
}
|
||||
http_request_simple_response(&r->http, result, message);
|
||||
return result;
|
||||
http_request_simple_response(&r->http, http_status, http_reason);
|
||||
return http_status;
|
||||
}
|
||||
|
||||
static HTTP_CONTENT_GENERATOR restful_rhizome_bundlelist_json_content;
|
||||
@ -411,60 +413,49 @@ static int insert_make_manifest(httpd_request *r)
|
||||
if (!r->u.insert.received_manifest)
|
||||
return http_response_form_part(r, 400, "Missing", PART_MANIFEST, NULL, 0);
|
||||
if ((r->manifest = rhizome_new_manifest()) == NULL)
|
||||
return http_request_rhizome_response(r, 429, "Manifest table full", NULL); // Too Many Requests
|
||||
return http_request_rhizome_response(r, 429, "Manifest table full"); // Too Many Requests
|
||||
assert(r->u.insert.manifest.length <= sizeof r->manifest->manifestdata);
|
||||
memcpy(r->manifest->manifestdata, r->u.insert.manifest.buffer, r->u.insert.manifest.length);
|
||||
r->manifest->manifest_all_bytes = r->u.insert.manifest.length;
|
||||
rhizome_manifest *mout = NULL;
|
||||
int n = rhizome_manifest_parse(r->manifest);
|
||||
switch (n) {
|
||||
case 0:
|
||||
if (!r->manifest->malformed)
|
||||
break;
|
||||
// fall through
|
||||
if (r->manifest->malformed) {
|
||||
r->bundle_result = rhizome_bundle_result_sprintf(RHIZOME_BUNDLE_STATUS_INVALID, "Malformed manifest: %s", r->manifest->malformed);
|
||||
} else {
|
||||
r->bundle_result = rhizome_manifest_add_file(r->u.insert.appending, r->manifest, &mout,
|
||||
r->u.insert.received_bundleid ? &r->bid : NULL,
|
||||
r->u.insert.received_secret ? &r->u.insert.bundle_secret : NULL,
|
||||
r->u.insert.received_author ? &r->u.insert.author : NULL,
|
||||
NULL, 0, NULL);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
rhizome_manifest_free(r->manifest);
|
||||
r->manifest = NULL;
|
||||
r->bundle_status = RHIZOME_BUNDLE_STATUS_INVALID;
|
||||
return http_request_rhizome_response(r, 422, "Malformed manifest", NULL); // Unprocessable Entity
|
||||
r->bundle_result = rhizome_bundle_result_static(RHIZOME_BUNDLE_STATUS_INVALID, "Invalid manifest");
|
||||
break;
|
||||
default:
|
||||
WHYF("rhizome_manifest_parse() returned %d", n);
|
||||
// fall through
|
||||
case -1:
|
||||
r->bundle_status = RHIZOME_BUNDLE_STATUS_ERROR;
|
||||
r->bundle_result = rhizome_bundle_result_static(RHIZOME_BUNDLE_STATUS_ERROR, "Error while parsing manifest");
|
||||
break;
|
||||
}
|
||||
rhizome_manifest *mout = NULL;
|
||||
char message[150];
|
||||
enum rhizome_add_file_result result = rhizome_manifest_add_file(r->u.insert.appending, r->manifest, &mout,
|
||||
r->u.insert.received_bundleid ? &r->bid: NULL,
|
||||
r->u.insert.received_secret ? &r->u.insert.bundle_secret : NULL,
|
||||
r->u.insert.received_author ? &r->u.insert.author: NULL,
|
||||
NULL, 0, NULL, strbuf_local_buf(message));
|
||||
int result_valid = 0;
|
||||
switch (result) {
|
||||
case RHIZOME_ADD_FILE_ERROR:
|
||||
return http_request_rhizome_response(r, 500, message, NULL);
|
||||
case RHIZOME_ADD_FILE_OK:
|
||||
result_valid = 1;
|
||||
switch (r->bundle_result.status) {
|
||||
case RHIZOME_BUNDLE_STATUS_NEW:
|
||||
case RHIZOME_BUNDLE_STATUS_OLD:
|
||||
case RHIZOME_BUNDLE_STATUS_SAME:
|
||||
case RHIZOME_BUNDLE_STATUS_DUPLICATE:
|
||||
case RHIZOME_BUNDLE_STATUS_NO_ROOM:
|
||||
break;
|
||||
case RHIZOME_ADD_FILE_INVALID:
|
||||
r->bundle_status = RHIZOME_BUNDLE_STATUS_INVALID; // TODO separate enum for CLI return codes
|
||||
return http_request_rhizome_response(r, 422, message, NULL); // Unprocessable Entity
|
||||
case RHIZOME_ADD_FILE_BUSY:
|
||||
r->bundle_status = RHIZOME_BUNDLE_STATUS_BUSY; // TODO separate enum for CLI return codes
|
||||
return http_request_rhizome_response(r, 423, message, NULL); // Locked
|
||||
case RHIZOME_ADD_FILE_REQUIRES_JOURNAL:
|
||||
r->bundle_status = RHIZOME_BUNDLE_STATUS_INVALID; // TODO separate enum for CLI return codes
|
||||
return http_request_rhizome_response(r, 422, message, NULL); // Unprocessable Entity
|
||||
case RHIZOME_ADD_FILE_INVALID_FOR_JOURNAL:
|
||||
r->bundle_status = RHIZOME_BUNDLE_STATUS_INVALID; // TODO separate enum for CLI return codes
|
||||
return http_request_rhizome_response(r, 422, message, NULL); // Unprocessable Entity
|
||||
case RHIZOME_ADD_FILE_WRONG_SECRET:
|
||||
r->bundle_status = RHIZOME_BUNDLE_STATUS_READONLY; // TODO separate enum for CLI return codes
|
||||
return http_request_rhizome_response(r, 419, message, NULL); // Authentication Timeout
|
||||
case RHIZOME_BUNDLE_STATUS_INCONSISTENT:
|
||||
case RHIZOME_BUNDLE_STATUS_INVALID:
|
||||
case RHIZOME_BUNDLE_STATUS_BUSY:
|
||||
case RHIZOME_BUNDLE_STATUS_FAKE:
|
||||
case RHIZOME_BUNDLE_STATUS_READONLY:
|
||||
case RHIZOME_BUNDLE_STATUS_ERROR:
|
||||
return http_request_rhizome_response(r, 0, NULL);
|
||||
}
|
||||
if (!result_valid)
|
||||
FATALF("result = %d", result);
|
||||
assert(mout != NULL);
|
||||
if (mout != r->manifest) {
|
||||
rhizome_manifest_free(r->manifest);
|
||||
@ -540,7 +531,7 @@ static int insert_mime_part_header(struct http_request *hr, const struct mime_pa
|
||||
r->payload_status = rhizome_write_open_journal(&r->u.insert.write, r->manifest, 0, RHIZOME_SIZE_UNSET);
|
||||
if (r->payload_status == RHIZOME_PAYLOAD_STATUS_ERROR) {
|
||||
WHYF("rhizome_write_open_journal() returned %d %s", r->payload_status, rhizome_payload_status_message(r->payload_status));
|
||||
return http_request_rhizome_response(r, 500, "Error in payload open for write (journal)", NULL);
|
||||
return http_request_rhizome_response(r, 500, "Error in payload open for write (journal)");
|
||||
}
|
||||
} else {
|
||||
// Note: r->manifest->filesize can be RHIZOME_SIZE_UNSET at this point, if the manifest did
|
||||
@ -548,7 +539,7 @@ static int insert_mime_part_header(struct http_request *hr, const struct mime_pa
|
||||
r->payload_status = rhizome_write_open_manifest(&r->u.insert.write, r->manifest);
|
||||
if (r->payload_status == RHIZOME_PAYLOAD_STATUS_ERROR) {
|
||||
WHYF("rhizome_write_open_manifest() returned %d %s", r->payload_status, rhizome_payload_status_message(r->payload_status));
|
||||
return http_request_rhizome_response(r, 500, "Error in payload open for write", NULL);
|
||||
return http_request_rhizome_response(r, 500, "Error in payload open for write");
|
||||
}
|
||||
}
|
||||
switch (r->payload_status) {
|
||||
@ -597,7 +588,7 @@ static int insert_mime_part_body(struct http_request *hr, char *buf, size_t len)
|
||||
switch (r->payload_status) {
|
||||
case RHIZOME_PAYLOAD_STATUS_NEW:
|
||||
if (rhizome_write_buffer(&r->u.insert.write, (unsigned char *)buf, len) == -1)
|
||||
return http_request_rhizome_response(r, 500, "Error in payload write", NULL);
|
||||
return http_request_rhizome_response(r, 500, "Error in payload write");
|
||||
break;
|
||||
case RHIZOME_PAYLOAD_STATUS_STORED:
|
||||
// TODO: calculate payload hash so it can be compared with stored payload
|
||||
@ -690,55 +681,50 @@ static int restful_rhizome_insert_end(struct http_request *hr)
|
||||
status_valid = 1;
|
||||
break;
|
||||
case RHIZOME_PAYLOAD_STATUS_WRONG_SIZE:
|
||||
r->bundle_status = RHIZOME_BUNDLE_STATUS_INCONSISTENT;
|
||||
{
|
||||
strbuf msg = strbuf_alloca(200);
|
||||
strbuf_sprintf(msg, "Payload size (%"PRIu64") contradicts manifest (filesize=%"PRIu64")", r->u.insert.payload_size, r->manifest->filesize);
|
||||
return http_request_rhizome_response(r, 422, "Inconsistent filesize", strbuf_str(msg)); // Unprocessable Entity
|
||||
}
|
||||
r->bundle_result = rhizome_bundle_result_sprintf(RHIZOME_BUNDLE_STATUS_INCONSISTENT,
|
||||
"Payload size (%"PRIu64") contradicts manifest (filesize=%"PRIu64")",
|
||||
r->u.insert.payload_size, r->manifest->filesize);
|
||||
return http_request_rhizome_response(r, 0, "Inconsistent filesize");
|
||||
case RHIZOME_PAYLOAD_STATUS_WRONG_HASH:
|
||||
r->bundle_status = RHIZOME_BUNDLE_STATUS_INCONSISTENT;
|
||||
{
|
||||
strbuf msg = strbuf_alloca(200);
|
||||
strbuf_sprintf(msg, "Payload hash (%s) contradicts manifest (filehash=%s)",
|
||||
alloca_tohex_rhizome_filehash_t(r->u.insert.write.id),
|
||||
alloca_tohex_rhizome_filehash_t(r->manifest->filehash));
|
||||
return http_request_rhizome_response(r, 422, "Inconsistent filehash", strbuf_str(msg)); // Unprocessable Entity
|
||||
}
|
||||
r->bundle_result = rhizome_bundle_result_sprintf(RHIZOME_BUNDLE_STATUS_INCONSISTENT,
|
||||
"Payload hash (%s) contradicts manifest (filehash=%s)",
|
||||
alloca_tohex_rhizome_filehash_t(r->u.insert.write.id),
|
||||
alloca_tohex_rhizome_filehash_t(r->manifest->filehash));
|
||||
return http_request_rhizome_response(r, 0, "Inconsistent filehash");
|
||||
case RHIZOME_PAYLOAD_STATUS_CRYPTO_FAIL:
|
||||
r->bundle_status = RHIZOME_BUNDLE_STATUS_READONLY;
|
||||
return http_request_rhizome_response(r, 419, "Missing bundle secret", NULL); // Authentication Timeout
|
||||
r->bundle_result = rhizome_bundle_result(RHIZOME_BUNDLE_STATUS_READONLY);
|
||||
return http_request_rhizome_response(r, 0, NULL);
|
||||
case RHIZOME_PAYLOAD_STATUS_TOO_BIG:
|
||||
r->bundle_status = RHIZOME_BUNDLE_STATUS_NO_ROOM;
|
||||
return http_request_rhizome_response(r, 202, "Bundle too big", NULL); // Accepted
|
||||
r->bundle_result = rhizome_bundle_result(RHIZOME_BUNDLE_STATUS_NO_ROOM);
|
||||
return http_request_rhizome_response(r, 0, NULL);
|
||||
case RHIZOME_PAYLOAD_STATUS_EVICTED:
|
||||
r->bundle_status = RHIZOME_BUNDLE_STATUS_NO_ROOM;
|
||||
return http_request_rhizome_response(r, 202, "Bundle evicted", NULL); // Accepted
|
||||
r->bundle_result = rhizome_bundle_result(RHIZOME_BUNDLE_STATUS_NO_ROOM);
|
||||
return http_request_rhizome_response(r, 0, NULL);
|
||||
case RHIZOME_PAYLOAD_STATUS_ERROR:
|
||||
return http_request_rhizome_response(r, 500, "Payload store error", NULL);
|
||||
return http_request_rhizome_response(r, 500, "Payload store error");
|
||||
}
|
||||
if (!status_valid)
|
||||
FATALF("rhizome_finish_store() returned status = %d", r->payload_status);
|
||||
// Finalise the manifest and add it to the store.
|
||||
const char *invalid_reason = rhizome_manifest_validate_reason(r->manifest);
|
||||
if (invalid_reason) {
|
||||
r->bundle_status = RHIZOME_BUNDLE_STATUS_INVALID;
|
||||
return http_request_rhizome_response(r, 422, invalid_reason, NULL); // Unprocessable Entity
|
||||
r->bundle_result = rhizome_bundle_result_static(RHIZOME_BUNDLE_STATUS_INVALID, invalid_reason);
|
||||
return http_request_rhizome_response(r, 0, NULL);
|
||||
}
|
||||
if (r->manifest->malformed) {
|
||||
r->bundle_status = RHIZOME_BUNDLE_STATUS_INVALID;
|
||||
return http_request_rhizome_response(r, 422, r->manifest->malformed, NULL); // Unprocessable Entity
|
||||
r->bundle_result = rhizome_bundle_result_static(RHIZOME_BUNDLE_STATUS_INVALID, r->manifest->malformed);
|
||||
return http_request_rhizome_response(r, 0, NULL);
|
||||
}
|
||||
if (!r->manifest->haveSecret) {
|
||||
r->bundle_status = RHIZOME_BUNDLE_STATUS_READONLY;
|
||||
return http_request_rhizome_response(r, 419, "Missing bundle secret", NULL); // Authentication Timeout
|
||||
r->bundle_result = rhizome_bundle_result_static(RHIZOME_BUNDLE_STATUS_READONLY, "Missing bundle secret");
|
||||
return http_request_rhizome_response(r, 0, NULL);
|
||||
}
|
||||
rhizome_manifest *mout = NULL;
|
||||
r->bundle_status = rhizome_manifest_finalise(r->manifest, &mout, !r->u.insert.force_new);
|
||||
rhizome_bundle_result_free(&r->bundle_result);
|
||||
r->bundle_result.status = rhizome_manifest_finalise(r->manifest, &mout, !r->u.insert.force_new);
|
||||
int result = 500;
|
||||
const char *message = NULL;
|
||||
DEBUGF(rhizome, "r->bundle_status=%d", r->bundle_status);
|
||||
switch (r->bundle_status) {
|
||||
DEBUGF(rhizome, "r->bundle_result = %s", alloca_rhizome_bundle_result(r->bundle_result));
|
||||
switch (r->bundle_result.status) {
|
||||
case RHIZOME_BUNDLE_STATUS_NEW:
|
||||
if (mout && mout != r->manifest)
|
||||
rhizome_manifest_free(mout);
|
||||
@ -754,7 +740,7 @@ static int restful_rhizome_insert_end(struct http_request *hr)
|
||||
result = 201;
|
||||
break;
|
||||
case RHIZOME_BUNDLE_STATUS_ERROR:
|
||||
message = "Error in manifest finalise";
|
||||
r->bundle_result.message = "Error in manifest finalise";
|
||||
// fall through
|
||||
case RHIZOME_BUNDLE_STATUS_INVALID:
|
||||
case RHIZOME_BUNDLE_STATUS_FAKE:
|
||||
@ -766,10 +752,10 @@ static int restful_rhizome_insert_end(struct http_request *hr)
|
||||
rhizome_manifest_free(mout);
|
||||
rhizome_manifest_free(r->manifest);
|
||||
r->manifest = NULL;
|
||||
return http_request_rhizome_response(r, 0, message, NULL);
|
||||
return http_request_rhizome_response(r, 0, NULL);
|
||||
}
|
||||
if (result == 500)
|
||||
FATALF("rhizome_manifest_finalise() returned status = %d", r->bundle_status);
|
||||
FATALF("rhizome_manifest_finalise() returned status = %d", r->bundle_result.status);
|
||||
rhizome_authenticate_author(r->manifest);
|
||||
http_request_response_static(&r->http, result, "rhizome-manifest/text",
|
||||
(const char *)r->manifest->manifestdata, r->manifest->manifest_all_bytes
|
||||
@ -810,9 +796,9 @@ static int restful_rhizome_(httpd_request *r, const char *remainder)
|
||||
if (r->http.verb != HTTP_VERB_GET)
|
||||
return 405;
|
||||
if ((r->manifest = rhizome_new_manifest()) == NULL)
|
||||
return http_request_rhizome_response(r, 429, "Manifest table full", NULL); // Too Many Requests
|
||||
r->bundle_status = rhizome_retrieve_manifest(&bid, r->manifest);
|
||||
switch(r->bundle_status){
|
||||
return http_request_rhizome_response(r, 429, "Manifest table full"); // Too Many Requests
|
||||
r->bundle_result.status = rhizome_retrieve_manifest(&bid, r->manifest);
|
||||
switch(r->bundle_result.status){
|
||||
case RHIZOME_BUNDLE_STATUS_SAME:
|
||||
rhizome_authenticate_author(r->manifest);
|
||||
break;
|
||||
@ -822,13 +808,13 @@ static int restful_rhizome_(httpd_request *r, const char *remainder)
|
||||
break;
|
||||
case RHIZOME_BUNDLE_STATUS_BUSY:
|
||||
rhizome_manifest_free(r->manifest);
|
||||
return http_request_rhizome_response(r, 423, "Database busy", NULL); // Locked
|
||||
return http_request_rhizome_response(r, 0, NULL);
|
||||
case RHIZOME_BUNDLE_STATUS_ERROR:
|
||||
rhizome_manifest_free(r->manifest);
|
||||
r->manifest = NULL;
|
||||
return http_request_rhizome_response(r, 500, "Manifest retrieve error", NULL);
|
||||
return http_request_rhizome_response(r, 500, "Manifest retrieve error");
|
||||
default: // should not return others
|
||||
FATALF("rhizome_retrieve_manifest() returned status = %d", r->bundle_status);
|
||||
FATALF("rhizome_retrieve_manifest() returned status = %d", r->bundle_result.status);
|
||||
}
|
||||
return handler(r, remainder);
|
||||
}
|
||||
@ -838,7 +824,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, "Bundle not found", NULL); // Not Found
|
||||
return http_request_rhizome_response(r, 404, "Bundle not found"); // Not Found
|
||||
http_request_response_static(&r->http, 200, "rhizome-manifest/text",
|
||||
(const char *)r->manifest->manifestdata, r->manifest->manifest_all_bytes
|
||||
);
|
||||
@ -850,7 +836,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, "Bundle not found", NULL); // Not Found
|
||||
return http_request_rhizome_response(r, 404, "Bundle not found"); // Not Found
|
||||
if (r->manifest->filesize == 0) {
|
||||
http_request_response_static(&r->http, 200, CONTENT_TYPE_BLOB, "", 0);
|
||||
return 1;
|
||||
@ -867,7 +853,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, "Bundle not found", NULL); // Not Found
|
||||
return http_request_rhizome_response(r, 404, "Bundle not found"); // Not Found
|
||||
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);
|
||||
@ -885,7 +871,7 @@ static int rhizome_response_content_init_read_state(httpd_request *r)
|
||||
{
|
||||
if (r->u.read_state.length == RHIZOME_SIZE_UNSET && rhizome_read(&r->u.read_state, NULL, 0)) {
|
||||
rhizome_read_close(&r->u.read_state);
|
||||
return http_request_rhizome_response(r, 404, "Payload not found", NULL);
|
||||
return http_request_rhizome_response(r, 404, "Payload not found");
|
||||
}
|
||||
assert(r->u.read_state.length != RHIZOME_SIZE_UNSET);
|
||||
int ret = http_response_init_content_range(r, r->u.read_state.length);
|
||||
@ -906,14 +892,14 @@ int rhizome_response_content_init_filehash(httpd_request *r, const rhizome_fileh
|
||||
case RHIZOME_PAYLOAD_STATUS_STORED:
|
||||
return rhizome_response_content_init_read_state(r);
|
||||
case RHIZOME_PAYLOAD_STATUS_NEW:
|
||||
return http_request_rhizome_response(r, 404, "Payload not found", NULL);
|
||||
return http_request_rhizome_response(r, 404, "Payload not found");
|
||||
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 http_request_rhizome_response(r, 500, "Payload read error", NULL);
|
||||
return http_request_rhizome_response(r, 500, "Payload read error");
|
||||
}
|
||||
FATALF("rhizome_open_read() returned status = %d", r->payload_status);
|
||||
}
|
||||
@ -930,15 +916,15 @@ int rhizome_response_content_init_payload(httpd_request *r, rhizome_manifest *m)
|
||||
case RHIZOME_PAYLOAD_STATUS_STORED:
|
||||
return rhizome_response_content_init_read_state(r);
|
||||
case RHIZOME_PAYLOAD_STATUS_NEW:
|
||||
return http_request_rhizome_response(r, 404, "Payload not found", NULL);
|
||||
return http_request_rhizome_response(r, 404, "Payload not found");
|
||||
case RHIZOME_PAYLOAD_STATUS_CRYPTO_FAIL:
|
||||
return http_request_rhizome_response(r, 419, NULL, NULL); // Authentication Timeout
|
||||
return http_request_rhizome_response(r, 419, "Payload decryption error"); // Authentication Timeout
|
||||
case RHIZOME_PAYLOAD_STATUS_ERROR:
|
||||
case RHIZOME_PAYLOAD_STATUS_WRONG_SIZE:
|
||||
case RHIZOME_PAYLOAD_STATUS_WRONG_HASH:
|
||||
case RHIZOME_PAYLOAD_STATUS_TOO_BIG:
|
||||
case RHIZOME_PAYLOAD_STATUS_EVICTED:
|
||||
return http_request_rhizome_response(r, 500, "Payload read error", NULL);
|
||||
return http_request_rhizome_response(r, 500, "Payload read error");
|
||||
}
|
||||
FATALF("rhizome_open_decrypt_read() returned status = %d", r->payload_status);
|
||||
}
|
||||
@ -974,14 +960,30 @@ 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);
|
||||
switch (r->bundle_result.status) {
|
||||
case RHIZOME_BUNDLE_STATUS_NEW:
|
||||
case RHIZOME_BUNDLE_STATUS_SAME:
|
||||
case RHIZOME_BUNDLE_STATUS_DUPLICATE:
|
||||
case RHIZOME_BUNDLE_STATUS_OLD:
|
||||
case RHIZOME_BUNDLE_STATUS_INVALID:
|
||||
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_BUSY:
|
||||
case RHIZOME_BUNDLE_STATUS_ERROR:
|
||||
strbuf_sprintf(sb, "Serval-Rhizome-Result-Bundle-Status-Code: %d\r\n", r->bundle_result.status);
|
||||
strbuf_puts(sb, "Serval-Rhizome-Result-Bundle-Status-Message: ");
|
||||
strbuf_json_string(sb, rhizome_bundle_result_message_nonnull(r->bundle_result));
|
||||
strbuf_puts(sb, "\r\n");
|
||||
break;
|
||||
}
|
||||
if ((status_message = rhizome_payload_status_message(r->payload_status))) {
|
||||
const char *status_message = rhizome_payload_status_message(r->payload_status);
|
||||
if (status_message) {
|
||||
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);
|
||||
strbuf_puts(sb, "Serval-Rhizome-Result-Payload-Status-Message: ");
|
||||
strbuf_json_string(sb, status_message);
|
||||
strbuf_puts(sb, "\r\n");
|
||||
}
|
||||
rhizome_manifest *m = r->manifest;
|
||||
if (m) {
|
||||
|
@ -808,7 +808,7 @@ setup_AddUpdateNoAuthorWithSecret() {
|
||||
setup_AddUpdateNoAuthor
|
||||
}
|
||||
test_AddUpdateNoAuthorWithSecret() {
|
||||
executeOk_servald rhizome add file $SIDA file1_2 file1_2.manifest "$file1_secret"
|
||||
executeOk_servald rhizome add file '' file1_2 file1_2.manifest "$file1_secret"
|
||||
tfw_cat --stderr
|
||||
# Rhizome store contents have new payload, but it has lost its author (no BK
|
||||
# field any more).
|
||||
@ -1083,7 +1083,7 @@ setup_JournalAddCreate() {
|
||||
test_JournalAddCreate() {
|
||||
# TODO: servald should return a status code reserved for this case, instead
|
||||
# of the 4 error (which means "invalid manifest")
|
||||
execute --exit-status=4 $servald rhizome add file $SIDA file1 file1.manifest
|
||||
execute --exit-status=4 --stderr $servald rhizome add file $SIDA file1 file1.manifest
|
||||
tfw_cat --stdout --stderr
|
||||
}
|
||||
|
||||
|
@ -483,7 +483,7 @@ test_RhizomePayloadDecryptedForeign() {
|
||||
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\$"
|
||||
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"
|
||||
|
Loading…
x
Reference in New Issue
Block a user