diff --git a/http_server.c b/http_server.c index 4f340ddb..c5d82b6e 100644 --- a/http_server.c +++ b/http_server.c @@ -1118,7 +1118,7 @@ static int http_request_start_body(struct http_request *r) else if (r->verb == HTTP_VERB_POST) { if (r->request_header.content_length == CONTENT_LENGTH_UNKNOWN) { IDEBUGF(r->debug, "Malformed HTTP %s request: missing Content-Length header", r->verb); - return 411; + return 411; // Length Required } if (r->request_header.content_length == 0) { r->parser = http_request_reject_content; @@ -1142,7 +1142,7 @@ static int http_request_start_body(struct http_request *r) } else { IDEBUGF(r->debug, "Unsupported HTTP %s request: Content-Type %s not supported", r->verb, alloca_mime_content_type(&r->request_header.content_type)); - return 415; + return 415; // Unsupported Media Type } } } @@ -1917,6 +1917,9 @@ static const char *httpResultString(int response_code) case 414: return "Request-URI Too Long"; case 415: return "Unsupported Media Type"; case 416: return "Requested Range Not Satisfiable"; + case 422: return "Unprocessable Entity"; + case 423: return "Locked"; + case 429: return "Too Many Requests"; case 431: return "Request Header Fields Too Large"; case 500: return "Internal Server Error"; case 501: return "Not Implemented"; diff --git a/java/org/servalproject/servaldna/rhizome/RhizomeCommon.java b/java/org/servalproject/servaldna/rhizome/RhizomeCommon.java index 1159e2a5..058b3838 100644 --- a/java/org/servalproject/servaldna/rhizome/RhizomeCommon.java +++ b/java/org/servalproject/servaldna/rhizome/RhizomeCommon.java @@ -93,10 +93,16 @@ protected static Status receiveResponse(HttpURLConnection conn, int[] expected_r JSONTokeniser json = new JSONTokeniser(new InputStreamReader(conn.getErrorStream(), "UTF-8")); decodeRestfulStatus(status, json); } - if (status.http_status_code == HttpURLConnection.HTTP_FORBIDDEN) + switch (status.http_status_code) { + case HttpURLConnection.HTTP_FORBIDDEN: // for crypto failure (missing secret) + case HttpURLConnection.HTTP_NOT_FOUND: // for unknown BID + case 422: // Unprocessable Entity, for invalid/malformed manifest + case 423: // Locked, for database busy + case 429: // Too Many Requests, for out of manifests return status; - if (status.http_status_code == HttpURLConnection.HTTP_NOT_IMPLEMENTED) + case HttpURLConnection.HTTP_NOT_IMPLEMENTED: throw new ServalDNotImplementedException(status.http_status_message); + } throw new ServalDInterfaceException("unexpected HTTP response: " + status.http_status_code + " " + status.http_status_message); } diff --git a/rhizome_database.c b/rhizome_database.c index 3be42902..2074b885 100644 --- a/rhizome_database.c +++ b/rhizome_database.c @@ -1658,6 +1658,14 @@ enum rhizome_bundle_status rhizome_find_duplicate(const rhizome_manifest *m, rhi return ret; } +/* Unpacks a database MANIFESTS table row into a manifest structure. + * + * Returns RHIZOME_BUNDLE_STATUS_SAME if unpack succeeds + * Returns RHIZOME_BUNDLE_STATUS_NEW if manifest is not found + * Returns RHIZOME_BUNDLE_STATUS_ERROR on error + * Returns RHIZOME_BUNDLE_STATUS_BUSY if the database is locked + * Caller is responsible for allocating and freeing rhizome_manifest + */ static enum rhizome_bundle_status unpack_manifest_row(sqlite_retry_state *retry, rhizome_manifest *m, sqlite3_stmt *statement) { int r=sqlite_step_retry(retry, statement); diff --git a/rhizome_direct_http.c b/rhizome_direct_http.c index deef5f8b..8fd6510f 100644 --- a/rhizome_direct_http.c +++ b/rhizome_direct_http.c @@ -107,22 +107,22 @@ static int rhizome_direct_import_end(struct http_request *hr) http_request_simple_response(&r->http, 201, "Bundle succesfully imported"); return 0; case RHIZOME_BUNDLE_STATUS_SAME: - http_request_simple_response(&r->http, 200, "Bundle already imported"); + http_request_simple_response(&r->http, 200, "Bundle already imported"); // OK return 0; case RHIZOME_BUNDLE_STATUS_OLD: - http_request_simple_response(&r->http, 403, "Newer bundle already stored"); + http_request_simple_response(&r->http, 202, "Newer bundle already stored"); // Accepted return 0; case RHIZOME_BUNDLE_STATUS_INVALID: - http_request_simple_response(&r->http, 403, "Manifest is invalid"); + http_request_simple_response(&r->http, 422, "Manifest is invalid"); // Unprocessable Entity return 0; case RHIZOME_BUNDLE_STATUS_INCONSISTENT: - http_request_simple_response(&r->http, 403, "Manifest is inconsistent with file"); + http_request_simple_response(&r->http, 422, "Manifest is inconsistent with file"); // Unprocessable Entity return 0; case RHIZOME_BUNDLE_STATUS_FAKE: - http_request_simple_response(&r->http, 403, "Manifest not signed"); + http_request_simple_response(&r->http, 403, "Manifest not signed"); // Forbidden return 0; case RHIZOME_BUNDLE_STATUS_NO_ROOM: - http_request_simple_response(&r->http, 403, "Not enough space"); + http_request_simple_response(&r->http, 202, "Not enough space"); // Accepted return 0; case RHIZOME_BUNDLE_STATUS_READONLY: case RHIZOME_BUNDLE_STATUS_DUPLICATE: diff --git a/rhizome_restful.c b/rhizome_restful.c index 82c8d866..ccc735ed 100644 --- a/rhizome_restful.c +++ b/rhizome_restful.c @@ -75,22 +75,28 @@ static int http_request_rhizome_response(struct httpd_request *r, uint16_t resul uint16_t rhizome_result = 0; switch (r->bundle_status) { case RHIZOME_BUNDLE_STATUS_NEW: + rhizome_result = 201; // Created + break; case RHIZOME_BUNDLE_STATUS_SAME: case RHIZOME_BUNDLE_STATUS_DUPLICATE: - rhizome_result = 201; + rhizome_result = 200; // OK break; - case RHIZOME_BUNDLE_STATUS_OLD: case RHIZOME_BUNDLE_STATUS_NO_ROOM: - rhizome_result = 200; + case RHIZOME_BUNDLE_STATUS_OLD: + rhizome_result = 202; // Accepted break; - case RHIZOME_BUNDLE_STATUS_INVALID: case RHIZOME_BUNDLE_STATUS_FAKE: - case RHIZOME_BUNDLE_STATUS_INCONSISTENT: case RHIZOME_BUNDLE_STATUS_READONLY: - rhizome_result = 403; + rhizome_result = 403; // Forbidden + break; + case RHIZOME_BUNDLE_STATUS_INVALID: + case RHIZOME_BUNDLE_STATUS_INCONSISTENT: + rhizome_result = 422; // Unprocessable Entity break; - case RHIZOME_BUNDLE_STATUS_ERROR: case RHIZOME_BUNDLE_STATUS_BUSY: + rhizome_result = 423; // Locked + break; + case RHIZOME_BUNDLE_STATUS_ERROR: rhizome_result = 500; break; } @@ -118,12 +124,14 @@ static int http_request_rhizome_response(struct httpd_request *r, uint16_t resul break; case RHIZOME_PAYLOAD_STATUS_TOO_BIG: case RHIZOME_PAYLOAD_STATUS_EVICTED: - rhizome_result = 200; + rhizome_result = 202; // Accepted + break; + case RHIZOME_PAYLOAD_STATUS_CRYPTO_FAIL: + rhizome_result = 403; // Forbidden break; case RHIZOME_PAYLOAD_STATUS_WRONG_SIZE: case RHIZOME_PAYLOAD_STATUS_WRONG_HASH: - case RHIZOME_PAYLOAD_STATUS_CRYPTO_FAIL: - rhizome_result = 403; + rhizome_result = 422; // Unprocessable Entity break; case RHIZOME_PAYLOAD_STATUS_ERROR: rhizome_result = 500; @@ -146,9 +154,9 @@ static int http_request_rhizome_response(struct httpd_request *r, uint16_t resul } if (result == 0) { result = 500; - message = NULL; + message = "Result logic error"; } - http_request_simple_response(&r->http, result, message ? message : result == 403 ? "Rhizome operation failed" : NULL); + http_request_simple_response(&r->http, result, message); return result; } @@ -159,7 +167,7 @@ static int restful_rhizome_bundlelist_json(httpd_request *r, const char *remaind r->http.response.header.content_type = CONTENT_TYPE_JSON; r->http.render_extra_headers = render_manifest_headers; if (!is_rhizome_http_enabled()) - return 403; + return 404; int ret = authorize_restful(&r->http); if (ret) return ret; @@ -191,7 +199,7 @@ static int restful_rhizome_newsince(httpd_request *r, const char *remainder) { r->http.response.header.content_type = CONTENT_TYPE_JSON; if (!is_rhizome_http_enabled()) - return 403; + return 404; int ret = authorize_restful(&r->http); if (ret) return ret; @@ -338,7 +346,7 @@ static 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 (!is_rhizome_http_enabled()) - return 403; + return 404; int ret = authorize_restful(&r->http); if (ret) return ret; @@ -389,7 +397,7 @@ static int insert_make_manifest(httpd_request *r) if (!r->u.insert.received_manifest) return http_response_form_part(r, "Missing", PART_MANIFEST, NULL, 0); if ((r->manifest = rhizome_new_manifest()) == NULL) - return http_request_rhizome_response(r, 500, "Internal Error: Out of manifests", NULL); + return http_request_rhizome_response(r, 429, "Manifest table full", NULL); // 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; @@ -403,7 +411,7 @@ static int insert_make_manifest(httpd_request *r) rhizome_manifest_free(r->manifest); r->manifest = NULL; r->bundle_status = RHIZOME_BUNDLE_STATUS_INVALID; - return http_request_rhizome_response(r, 403, "Malformed manifest", NULL); + return http_request_rhizome_response(r, 422, "Malformed manifest", NULL); // Unprocessable Entity default: WHYF("rhizome_manifest_parse() returned %d", n); // fall through @@ -427,19 +435,19 @@ static int insert_make_manifest(httpd_request *r) 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, 403, message, NULL); + 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, 403, message, NULL); + 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, 403, message, NULL); + 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, 403, message, NULL); + 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, 403, message, NULL); + return http_request_rhizome_response(r, 403, message, NULL); // Forbidden } if (!result_valid) FATALF("result = %d", result); @@ -518,7 +526,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 500; + return http_request_rhizome_response(r, 500, "Error in payload open for write (journal)", NULL); } } else { // Note: r->manifest->filesize can be RHIZOME_SIZE_UNSET at this point, if the manifest did @@ -526,7 +534,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 500; + return http_request_rhizome_response(r, 500, "Error in payload open for write", NULL); } } switch (r->payload_status) { @@ -575,7 +583,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 500; + return http_request_rhizome_response(r, 500, "Error in payload write", NULL); break; case RHIZOME_PAYLOAD_STATUS_STORED: // TODO: calculate payload hash so it can be compared with stored payload @@ -672,7 +680,7 @@ static int restful_rhizome_insert_end(struct http_request *hr) { 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, 403, "Inconsistent filesize", strbuf_str(msg)); + return http_request_rhizome_response(r, 422, "Inconsistent filesize", strbuf_str(msg)); // Unprocessable Entity } case RHIZOME_PAYLOAD_STATUS_WRONG_HASH: r->bundle_status = RHIZOME_BUNDLE_STATUS_INCONSISTENT; @@ -681,19 +689,19 @@ static int restful_rhizome_insert_end(struct http_request *hr) 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, 403, "Inconsistent filehash", strbuf_str(msg)); + return http_request_rhizome_response(r, 422, "Inconsistent filehash", strbuf_str(msg)); // Unprocessable Entity } case RHIZOME_PAYLOAD_STATUS_CRYPTO_FAIL: r->bundle_status = RHIZOME_BUNDLE_STATUS_READONLY; - return http_request_rhizome_response(r, 403, "Missing bundle secret", NULL); + return http_request_rhizome_response(r, 403, "Missing bundle secret", NULL); // Forbidden case RHIZOME_PAYLOAD_STATUS_TOO_BIG: r->bundle_status = RHIZOME_BUNDLE_STATUS_NO_ROOM; - return http_request_rhizome_response(r, 403, "Bundle too big", NULL); + return http_request_rhizome_response(r, 202, "Bundle too big", NULL); // Accepted case RHIZOME_PAYLOAD_STATUS_EVICTED: r->bundle_status = RHIZOME_BUNDLE_STATUS_NO_ROOM; - return http_request_rhizome_response(r, 403, "Bundle evicted", NULL); + return http_request_rhizome_response(r, 202, "Bundle evicted", NULL); // Accepted case RHIZOME_PAYLOAD_STATUS_ERROR: - return http_request_rhizome_response(r, 500, NULL, NULL); + return http_request_rhizome_response(r, 500, "Payload store error", NULL); } if (!status_valid) FATALF("rhizome_finish_store() returned status = %d", r->payload_status); @@ -701,19 +709,20 @@ static int restful_rhizome_insert_end(struct http_request *hr) 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, 403, invalid_reason, NULL); + return http_request_rhizome_response(r, 422, invalid_reason, NULL); // Unprocessable Entity } if (r->manifest->malformed) { r->bundle_status = RHIZOME_BUNDLE_STATUS_INVALID; - return http_request_rhizome_response(r, 403, r->manifest->malformed, NULL); + return http_request_rhizome_response(r, 422, r->manifest->malformed, NULL); // Unprocessable Entity } if (!r->manifest->haveSecret) { r->bundle_status = RHIZOME_BUNDLE_STATUS_READONLY; - return http_request_rhizome_response(r, 403, "Missing bundle secret", NULL); + return http_request_rhizome_response(r, 403, "Missing bundle secret", NULL); // Forbidden } rhizome_manifest *mout = NULL; r->bundle_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) { case RHIZOME_BUNDLE_STATUS_NEW: @@ -730,18 +739,20 @@ static int restful_rhizome_insert_end(struct http_request *hr) } result = 201; break; + case RHIZOME_BUNDLE_STATUS_ERROR: + message = "Error in manifest finalise"; + // fall through 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_ERROR: case RHIZOME_BUNDLE_STATUS_BUSY: if (mout && mout != r->manifest) rhizome_manifest_free(mout); rhizome_manifest_free(r->manifest); r->manifest = NULL; - return http_request_rhizome_response(r, 0, NULL, NULL); + return http_request_rhizome_response(r, 0, message, NULL); } if (result == 500) FATALF("rhizome_manifest_finalise() returned status = %d", r->bundle_status); @@ -761,7 +772,7 @@ static 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; + return 404; int ret = authorize_restful(&r->http); if (ret) return ret; @@ -785,7 +796,7 @@ 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 500; + 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){ case RHIZOME_BUNDLE_STATUS_SAME: @@ -795,10 +806,15 @@ static int restful_rhizome_(httpd_request *r, const char *remainder) rhizome_manifest_free(r->manifest); r->manifest = NULL; break; - default: + case RHIZOME_BUNDLE_STATUS_BUSY: + rhizome_manifest_free(r->manifest); + return http_request_rhizome_response(r, 423, "Database busy", NULL); // Locked + case RHIZOME_BUNDLE_STATUS_ERROR: rhizome_manifest_free(r->manifest); r->manifest = NULL; - return 500; + return http_request_rhizome_response(r, 500, "Manifest retrieve error", NULL); + default: // should not return others + FATALF("rhizome_retrieve_manifest() returned status = %d", r->bundle_status); } return handler(r, remainder); } @@ -808,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, 403, NULL, NULL); + return http_request_rhizome_response(r, 404, "Bundle not found", NULL); // Not Found http_request_response_static(&r->http, 200, "rhizome-manifest/text", (const char *)r->manifest->manifestdata, r->manifest->manifest_all_bytes ); @@ -820,14 +836,14 @@ 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, 403, NULL, NULL); + return http_request_rhizome_response(r, 404, "Bundle not found", NULL); // Not Found if (r->manifest->filesize == 0) { http_request_response_static(&r->http, 200, CONTENT_TYPE_BLOB, "", 0); return 1; } int ret = rhizome_response_content_init_filehash(r, &r->manifest->filehash); if (ret) - return http_request_rhizome_response(r, ret, NULL, NULL); + return ret; http_request_response_generated(&r->http, 200, CONTENT_TYPE_BLOB, rhizome_payload_content); return 1; } @@ -837,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, 403, NULL, NULL); + return http_request_rhizome_response(r, 404, "Bundle not found", NULL); // 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); @@ -845,7 +861,7 @@ static int restful_rhizome_bid_decrypted_bin(httpd_request *r, const char *remai } int ret = rhizome_response_content_init_payload(r, r->manifest); if (ret) - return http_request_rhizome_response(r, ret, NULL, NULL); + return ret; // TODO use Content Type from manifest (once it is implemented) http_request_response_generated(&r->http, 200, CONTENT_TYPE_BLOB, rhizome_payload_content); return 1; @@ -855,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 404; + return http_request_rhizome_response(r, 404, "Payload not found", NULL); } assert(r->u.read_state.length != RHIZOME_SIZE_UNSET); int ret = http_response_init_content_range(r, r->u.read_state.length); @@ -876,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 403; + return http_request_rhizome_response(r, 404, "Payload not found", NULL); 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; + return http_request_rhizome_response(r, 500, "Payload read error", NULL); } FATALF("rhizome_open_read() returned status = %d", r->payload_status); } @@ -900,14 +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); case RHIZOME_PAYLOAD_STATUS_CRYPTO_FAIL: - return 403; + return http_request_rhizome_response(r, 403, NULL, NULL); // Forbidden 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 -1; + return http_request_rhizome_response(r, 500, "Payload read error", NULL); } FATALF("rhizome_open_decrypt_read() returned status = %d", r->payload_status); } diff --git a/rhizome_store.c b/rhizome_store.c index 95b6fa41..4808a7c6 100644 --- a/rhizome_store.c +++ b/rhizome_store.c @@ -979,7 +979,9 @@ enum rhizome_payload_status rhizome_store_payload_file(rhizome_manifest *m, cons return rhizome_finish_store(&write, m, status); } -/* Return RHIZOME_PAYLOAD_STATUS_STORED if file blob found, RHIZOME_PAYLOAD_STATUS_NEW if not found. +/* Returns RHIZOME_PAYLOAD_STATUS_STORED if file blob found + * Returns RHIZOME_PAYLOAD_STATUS_NEW if not found + * Returns RHIZOME_PAYLOAD_STATUS_ERROR if unexpected error */ enum rhizome_payload_status rhizome_open_read(struct rhizome_read *read, const rhizome_filehash_t *hashp) { diff --git a/tests/rhizomerestful b/tests/rhizomerestful index 7d0dea59..f175e866 100755 --- a/tests/rhizomerestful +++ b/tests/rhizomerestful @@ -344,12 +344,13 @@ test_RhizomeManifestNonexist() { --basic --user harry:potter \ "http://$addr_localhost:$PORTA/restful/rhizome/$BID_NONEXISTENT.rhm" tfw_cat http.headers http.content - assertStdoutIs 403 + 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": 403})' + assertJq http.content 'contains({"http_status_code": 404})' + assertJq http.content 'contains({"http_status_message": "Bundle not found"})' assertJq http.content 'contains({"rhizome_bundle_status_code": 0})' assertJqGrep --ignore-case http.content '.rhizome_bundle_status_message' "bundle new to store" } @@ -392,12 +393,13 @@ test_RhizomePayloadRawNonexistManifest() { --basic --user harry:potter \ "http://$addr_localhost:$PORTA/restful/rhizome/$BID_NONEXISTENT/raw.bin" tfw_cat http.headers http.content - assertStdoutIs 403 + 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": 403})' + assertJq http.content 'contains({"http_status_code": 404})' + assertJq http.content 'contains({"http_status_message": "Bundle not found"})' assertJq http.content 'contains({"rhizome_bundle_status_code": 0})' assertJqGrep --ignore-case http.content '.rhizome_bundle_status_message' "bundle new to store" } @@ -419,12 +421,13 @@ test_RhizomePayloadRawNonexistPayload() { --basic --user harry:potter \ "http://$addr_localhost:$PORTA/restful/rhizome/${BID[0]}/raw.bin" tfw_cat http.headers http.content - assertStdoutIs 403 + assertStdoutIs 404 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({"http_status_code": 404})' + assertJq http.content 'contains({"http_status_message": "Payload not found"})' 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})' @@ -495,12 +498,13 @@ test_RhizomePayloadDecryptedNonexistManifest() { --basic --user harry:potter \ "http://$addr_localhost:$PORTA/restful/rhizome/$BID_NONEXISTENT/decrypted.bin" tfw_cat http.headers http.content - assertStdoutIs 403 + 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": 403})' + assertJq http.content 'contains({"http_status_code": 404})' + assertJq http.content 'contains({"http_status_message": "Bundle not found"})' assertJq http.content 'contains({"rhizome_bundle_status_code": 0})' assertJqGrep --ignore-case http.content '.rhizome_bundle_status_message' "bundle new to store" } @@ -522,12 +526,13 @@ test_RhizomePayloadDecryptedNonexistPayload() { --basic --user harry:potter \ "http://$addr_localhost:$PORTA/restful/rhizome/${BID[0]}/decrypted.bin" tfw_cat http.headers http.content - assertStdoutIs 403 + assertStdoutIs 404 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({"http_status_code": 404})' + assertJq http.content 'contains({"http_status_message": "Payload not found"})' 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})' @@ -972,8 +977,9 @@ test_RhizomeInsertJournalForbidden() { "http://$addr_localhost:$PORTA/restful/rhizome/insert" tfw_cat http.header http.body assertExitStatus == 0 - assertStdoutIs 403 - assertJq http.body 'contains({"http_status_code": 403})' + assertStdoutIs 422 + assertJq http.body 'contains({"http_status_code": 422})' + assertJq http.body 'contains({"http_status_message": "Cannot add a journal bundle (use append instead)"})' assertJqGrep --ignore-case http.body '.http_status_message' 'cannot add.*journal' executeOk_servald rhizome list assert_rhizome_list @@ -1097,8 +1103,9 @@ test_RhizomeInsertIncorrectFilesize() { "http://$addr_localhost:$PORTA/restful/rhizome/insert" tfw_cat http.header http.body assertExitStatus == 0 - assertStdoutIs 403 - assertJq http.body 'contains({"http_status_code": 403})' + assertStdoutIs 422 + assertJq http.body 'contains({"http_status_code": 422})' + assertJq http.body 'contains({"http_status_message": "Inconsistent filesize"})' assertJq http.body 'contains({"rhizome_payload_status_code": 3})' assertJqGrep --ignore-case http.body '.rhizome_payload_status_message' 'payload size.*contradicts manifest' execute curl \ @@ -1111,8 +1118,9 @@ test_RhizomeInsertIncorrectFilesize() { "http://$addr_localhost:$PORTA/restful/rhizome/insert" tfw_cat http.header http.body assertExitStatus == 0 - assertStdoutIs 403 - assertJq http.body 'contains({"http_status_code": 403})' + assertStdoutIs 422 + assertJq http.body 'contains({"http_status_code": 422})' + assertJq http.body 'contains({"http_status_message": "Inconsistent filesize"})' 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 @@ -1136,8 +1144,9 @@ test_RhizomeInsertIncorrectFilehash() { "http://$addr_localhost:$PORTA/restful/rhizome/insert" tfw_cat http.header http.body assertExitStatus == 0 - assertStdoutIs 403 - assertJq http.body 'contains({"http_status_code": 403})' + assertStdoutIs 422 + assertJq http.body 'contains({"http_status_code": 422})' + assertJq http.body 'contains({"http_status_message": "Inconsistent filehash"})' 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 @@ -1316,8 +1325,9 @@ test_RhizomeAppendNonJournalForbidden() { "http://$addr_localhost:$PORTA/restful/rhizome/append" tfw_cat http.header http.body assertExitStatus == 0 - assertStdoutIs 403 - assertJq http.body 'contains({"http_status_code": 403})' + assertStdoutIs 422 + assertJq http.body 'contains({"http_status_code": 422})' + assertJq http.body 'contains({"http_status_message": "Cannot append to a non-journal"})' assertJqGrep --ignore-case http.body '.http_status_message' 'cannot append.*non.*journal' executeOk_servald rhizome list assert_rhizome_list file1