diff --git a/rhizome.h b/rhizome.h index a95ad0d4..f8901693 100644 --- a/rhizome.h +++ b/rhizome.h @@ -758,6 +758,11 @@ typedef struct rhizome_http_request time_ms_t end_time; struct rhizome_list_cursor cursor; } list; + + /* For responses that contain a single manifest. + */ + rhizome_manifest *manifest; + } u; } rhizome_http_request; diff --git a/rhizome_http.c b/rhizome_http.c index d700a4cb..54a55f7e 100644 --- a/rhizome_http.c +++ b/rhizome_http.c @@ -565,6 +565,8 @@ static int restful_rhizome_bundlelist_json_content(struct http_request *hr, unsi return ret; } +static HTTP_RENDERER render_manifest_headers; + static int restful_rhizome_(rhizome_http_request *r, const char *remainder) { if (!is_rhizome_http_enabled()) @@ -583,8 +585,12 @@ static int restful_rhizome_(rhizome_http_request *r, const char *remainder) int ret = rhizome_retrieve_manifest(&bid, m); if (ret == -1) http_request_simple_response(&r->http, 500, NULL); - else if (ret == 0) + else if (ret == 0) { + rhizome_authenticate_author(m); + r->u.manifest = m; + r->http.render_extra_headers = render_manifest_headers; http_request_response_static(&r->http, 200, "x-servalproject/rhizome-manifest-text", (const char *)m->manifestdata, m->manifest_all_bytes); + } rhizome_manifest_free(m); return ret <= 0 ? 0 : 1; } @@ -766,6 +772,39 @@ static int fav_icon_header(rhizome_http_request *r, const char *remainder) return 0; } +static void render_manifest_headers(struct http_request *hr, strbuf sb) +{ + rhizome_http_request *r = (rhizome_http_request *) hr; + rhizome_manifest *m = r->u.manifest; + strbuf_sprintf(sb, "Serval-Rhizome-Bundle-Id: %s\r\n", alloca_tohex_rhizome_bid_t(m->cryptoSignPublic)); + strbuf_sprintf(sb, "Serval-Rhizome-Bundle-Version: %"PRIu64"\r\n", m->version); + strbuf_sprintf(sb, "Serval-Rhizome-Bundle-Filesize: %"PRIu64"\r\n", m->filesize); + if (m->filesize != 0) + strbuf_sprintf(sb, "Serval-Rhizome-Bundle-Filehash: %s\r\n", alloca_tohex_rhizome_filehash_t(m->filehash)); + if (m->has_bundle_key) + strbuf_sprintf(sb, "Serval-Rhizome-Bundle-BK: %s\r\n", alloca_tohex_rhizome_bk_t(m->bundle_key)); + if (m->has_date) + strbuf_sprintf(sb, "Serval-Rhizome-Bundle-Date: %"PRIu64"\r\n", m->date); + if (m->name) { + strbuf_puts(sb, "Serval-Rhizome-Bundle-Name: "); + strbuf_append_quoted_string(sb, m->name); + strbuf_puts(sb, "\r\n"); + } + if (m->service) + strbuf_sprintf(sb, "Serval-Rhizome-Bundle-Service: %s\r\n", m->service); + assert(m->authorship != AUTHOR_LOCAL); + if (m->authorship == AUTHOR_AUTHENTIC) + strbuf_sprintf(sb, "Serval-Rhizome-Bundle-Author: %s\r\n", alloca_tohex_sid_t(m->author)); + assert(m->haveSecret); + { + char secret[RHIZOME_BUNDLE_KEY_STRLEN + 1]; + rhizome_bytes_to_hex_upper(m->cryptoSignSecret, secret, RHIZOME_BUNDLE_KEY_BYTES); + strbuf_sprintf(sb, "Serval-Rhizome-Bundle-Secret: %s\r\n", secret); + } + strbuf_sprintf(sb, "Serval-Rhizome-Bundle-Rowid: %"PRIu64"\r\n", m->rowid); + strbuf_sprintf(sb, "Serval-Rhizome-Bundle-Inserttime: %"PRIu64"\r\n", m->inserttime); +} + static int root_page(rhizome_http_request *r, const char *remainder) { if (*remainder) diff --git a/testdefs_rhizome.sh b/testdefs_rhizome.sh index 631371cd..8666ccb5 100644 --- a/testdefs_rhizome.sh +++ b/testdefs_rhizome.sh @@ -298,6 +298,10 @@ extract_stdout_version() { extract_stdout_keyvalue "$1" version "$rexp_version" } +extract_stdout_author() { + extract_stdout_keyvalue "$1" .author "$rexp_author" +} + extract_stdout_secret() { extract_stdout_keyvalue "$1" .secret "$rexp_bundlesecret" } diff --git a/tests/rhizomehttp b/tests/rhizomehttp index 1542eb16..5ba26dd7 100755 --- a/tests/rhizomehttp +++ b/tests/rhizomehttp @@ -69,7 +69,7 @@ test_AuthBasicMissing() { --dump-header http.headers \ "http://$addr_localhost:$PORTA/restful/rhizome/bundlelist.json" assertStdoutIs '401' - assertGrep http.headers "^WWW-Authenticate: Basic realm=\"Serval Rhizome\"$CR$" + assertGrep http.headers "^WWW-Authenticate: Basic realm=\"Serval Rhizome\"$CR\$" } teardown_AuthBasicMissing() { tfw_cat http.headers http.output @@ -85,7 +85,7 @@ test_AuthBasicWrong() { --basic --user fred:nurks \ "http://$addr_localhost:$PORTA/restful/rhizome/bundlelist.json" assertStdoutIs '401' - assertGrep http.headers "^WWW-Authenticate: Basic realm=\"Serval Rhizome\"$CR$" + assertGrep http.headers "^WWW-Authenticate: Basic realm=\"Serval Rhizome\"$CR\$" executeOk curl \ --silent --fail --show-error --write-out '%{http_code}' \ --output http.output \ @@ -109,7 +109,11 @@ add_bundles() { extract_stdout_filesize SIZE[$n] extract_stdout_filehash HASH[$n] extract_stdout_date DATE[$n] + extract_stdout_BK BK[$n] extract_stdout_rowid ROWID[$n] + extract_stdout_author AUTHOR[$n] + extract_stdout_secret SECRET[$n] + extract_stdout_inserttime INSERTTIME[$n] [ "${ROWID[$n]}" -gt "${ROWID_MAX:-0}" ] && ROWID_MAX=${ROWID[$n]} done } @@ -303,14 +307,26 @@ test_RhizomeManifest() { executeOk curl \ --silent --fail --show-error \ --output bundle$n.rhm \ - --dump-header http.headers \ + --dump-header http.headers$n \ --basic --user harry:potter \ "http://$addr_localhost:$PORTA/restful/rhizome/${BID[$n]}.rhm" - tfw_cat http.headers bundle$n.rhm + tfw_cat http.headers$n bundle$n.rhm tfw_preserve bundle$n.rhm done for n in 0 1 2; do assert diff file$n.manifest bundle$n.rhm + assertGrep --matches=1 http.headers$n "^Serval-Rhizome-Bundle-Id: ${BID[$n]}$CR\$" + assertGrep --matches=1 http.headers$n "^Serval-Rhizome-Bundle-Version: ${VERSION[$n]}$CR\$" + assertGrep --matches=1 http.headers$n "^Serval-Rhizome-Bundle-Filesize: ${SIZE[$n]}$CR\$" + assertGrep --matches=1 http.headers$n "^Serval-Rhizome-Bundle-Filehash: ${HASH[$n]}$CR\$" + assertGrep --matches=1 http.headers$n "^Serval-Rhizome-Bundle-BK: ${BK[$n]}$CR\$" + assertGrep --matches=1 http.headers$n "^Serval-Rhizome-Bundle-Date: ${DATE[$n]}$CR\$" + assertGrep --matches=1 http.headers$n "^Serval-Rhizome-Bundle-Name: \"file$n\"$CR\$" + assertGrep --matches=1 http.headers$n "^Serval-Rhizome-Bundle-Service: file$CR\$" + assertGrep --matches=1 http.headers$n "^Serval-Rhizome-Bundle-Author: ${AUTHOR[$n]}$CR\$" + assertGrep --matches=1 http.headers$n "^Serval-Rhizome-Bundle-Secret: ${SECRET[$n]}$CR\$" + assertGrep --matches=1 http.headers$n "^Serval-Rhizome-Bundle-Inserttime: ${INSERTTIME[$n]}$CR\$" + assertGrep --matches=1 http.headers$n "^Serval-Rhizome-Bundle-Rowid: ${ROWID[$n]}$CR\$" done }