Implement HTTP GET /restful/rhizome/<BID>/raw.bin

This commit is contained in:
Andrew Bettison 2013-12-13 16:36:37 +10:30
parent 183cb46000
commit 6361bfd757
3 changed files with 134 additions and 52 deletions

View File

@ -744,6 +744,12 @@ typedef struct rhizome_http_request
// parameter (if any)
char data_file_name[MIME_FILENAME_MAXLEN + 1];
/* For responses that pertain to a single manifest.
*/
rhizome_manifest *manifest;
/* Mutually exclusive response arguments.
*/
union {
/* For responses that send part or all of a payload.
*/
@ -758,11 +764,6 @@ 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;

View File

@ -565,15 +565,31 @@ static int restful_rhizome_bundlelist_json_content(struct http_request *hr, unsi
return ret;
}
static int rhizome_payload_content_init(rhizome_http_request *r, const rhizome_filehash_t *hash);
static HTTP_CONTENT_GENERATOR rhizome_payload_content;
static HTTP_RENDERER render_manifest_headers;
static HTTP_HANDLER restful_rhizome_bid_rhm;
static HTTP_HANDLER restful_rhizome_bid_raw_bin;
static int restful_rhizome_(rhizome_http_request *r, const char *remainder)
{
if (!is_rhizome_http_enabled())
return 1;
HTTP_HANDLER *handler = NULL;
rhizome_bid_t bid;
const char *end;
if (!strn_to_rhizome_bid_t(&bid, remainder, &end) == -1 || strcmp(end, ".rhm") != 0)
if (strn_to_rhizome_bid_t(&bid, remainder, &end) != -1) {
if (strcmp(end, ".rhm") == 0) {
handler = restful_rhizome_bid_rhm;
remainder = "";
} else if (strcmp(end, "/raw.bin") == 0) {
handler = restful_rhizome_bid_raw_bin;
remainder = "";
}
}
if (handler == NULL)
return 1;
if (r->http.verb != HTTP_VERB_GET) {
http_request_simple_response(&r->http, 405, NULL);
@ -587,14 +603,48 @@ static int restful_rhizome_(rhizome_http_request *r, const char *remainder)
http_request_simple_response(&r->http, 500, NULL);
else if (ret == 0) {
rhizome_authenticate_author(m);
r->u.manifest = m;
r->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);
} else {
assert(r->manifest == NULL);
assert(r->http.render_extra_headers == NULL);
}
ret = handler(r, remainder);
rhizome_manifest_free(m);
return ret <= 0 ? 0 : 1;
}
static int restful_rhizome_bid_rhm(rhizome_http_request *r, const char *remainder)
{
if (remainder[0])
return 1;
if (r->manifest == NULL)
return 1;
http_request_response_static(&r->http, 200, "x-servalproject/rhizome-manifest-text",
(const char *)r->manifest->manifestdata, r->manifest->manifest_all_bytes
);
return 0;
}
static int restful_rhizome_bid_raw_bin(rhizome_http_request *r, const char *remainder)
{
if (remainder[0])
return 1;
if (r->manifest == NULL)
return 1;
if (r->manifest->filesize == 0) {
http_request_response_static(&r->http, 200, "application/binary", "", 0);
return 0;
}
int ret = rhizome_payload_content_init(r, &r->manifest->filehash);
if (ret == -1)
return 0;
if (ret)
return 1;
http_request_response_generated(&r->http, 200, "application/binary", rhizome_payload_content);
return 0;
}
static int neighbour_page(rhizome_http_request *r, const char *remainder)
{
if (r->http.verb != HTTP_VERB_GET) {
@ -661,7 +711,42 @@ static int rhizome_status_page(rhizome_http_request *r, const char *remainder)
return 0;
}
static int rhizome_file_content(struct http_request *hr, unsigned char *buf, size_t bufsz, struct http_content_generator_result *result)
static int rhizome_payload_content_init(rhizome_http_request *r, const rhizome_filehash_t *hash)
{
bzero(&r->u.read_state, sizeof r->u.read_state);
int n = rhizome_open_read(&r->u.read_state, hash);
if (n == -1) {
http_request_simple_response(&r->http, 500, NULL);
return -1;
}
if (n != 0)
return 1;
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 1;
}
assert(r->u.read_state.length != RHIZOME_SIZE_UNSET);
r->http.response.header.resource_length = r->u.read_state.length;
if (r->http.request_header.content_range_count > 0) {
assert(r->http.request_header.content_range_count == 1);
struct http_range closed;
unsigned n = http_range_close(&closed, r->http.request_header.content_ranges, 1, r->u.read_state.length);
if (n == 0 || http_range_bytes(&closed, 1) == 0) {
http_request_simple_response(&r->http, 416, NULL); // Request Range Not Satisfiable
return -1;
}
r->http.response.header.content_range_start = closed.first;
r->http.response.header.content_length = closed.last - closed.first + 1;
r->u.read_state.offset = closed.first;
} else {
r->http.response.header.content_range_start = 0;
r->http.response.header.content_length = r->http.response.header.resource_length;
r->u.read_state.offset = 0;
}
return 0;
}
static int rhizome_payload_content(struct http_request *hr, unsigned char *buf, size_t bufsz, struct http_content_generator_result *result)
{
// Only read multiples of 4k from disk.
const size_t blocksz = 1 << 12;
@ -707,37 +792,12 @@ static int rhizome_file_page(rhizome_http_request *r, const char *remainder)
rhizome_filehash_t filehash;
if (str_to_rhizome_filehash_t(&filehash, remainder) == -1)
return 1;
bzero(&r->u.read_state, sizeof r->u.read_state);
int n = rhizome_open_read(&r->u.read_state, &filehash);
if (n == -1) {
http_request_simple_response(&r->http, 500, NULL);
int ret = rhizome_payload_content_init(r, &filehash);
if (ret == -1)
return 0;
}
if (n != 0)
if (ret)
return 1;
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 1;
}
assert(r->u.read_state.length != RHIZOME_SIZE_UNSET);
r->http.response.header.resource_length = r->u.read_state.length;
if (r->http.request_header.content_range_count > 0) {
assert(r->http.request_header.content_range_count == 1);
struct http_range closed;
unsigned n = http_range_close(&closed, r->http.request_header.content_ranges, 1, r->u.read_state.length);
if (n == 0 || http_range_bytes(&closed, 1) == 0) {
http_request_simple_response(&r->http, 416, NULL); // Request Range Not Satisfiable
return 0;
}
r->http.response.header.content_range_start = closed.first;
r->http.response.header.content_length = closed.last - closed.first + 1;
r->u.read_state.offset = closed.first;
} else {
r->http.response.header.content_range_start = 0;
r->http.response.header.content_length = r->http.response.header.resource_length;
r->u.read_state.offset = 0;
}
http_request_response_generated(&r->http, 200, "application/binary", rhizome_file_content);
http_request_response_generated(&r->http, 200, "application/binary", rhizome_payload_content);
return 0;
}
@ -775,7 +835,7 @@ static int fav_icon_header(rhizome_http_request *r, const char *remainder)
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;
rhizome_manifest *m = r->manifest;
strbuf_sprintf(sb, "Serval-Rhizome-Bundle-Id: %s\r\n", alloca_tohex_rhizome_bid_t(m->cryptoSignPublic));
strbuf_sprintf(sb, "Serval-Rhizome-Bundle-Version: %"PRIu64"\r\n", m->version);
strbuf_sprintf(sb, "Serval-Rhizome-Bundle-Filesize: %"PRIu64"\r\n", m->filesize);

View File

@ -297,6 +297,22 @@ test_RhizomeNewSince() {
done
}
assert_http_response_headers() {
local n=$1
assertGrep --matches=1 http.headers$n "^Serval-Rhizome-Bundle-Id: ${BID[$n]}$CR\$"
assertGrep --matches=1 http.headers$n "^Serval-Rhizome-Bundle-Version: ${VERSION[$n]}$CR\$"
assertGrep --matches=1 http.headers$n "^Serval-Rhizome-Bundle-Filesize: ${SIZE[$n]}$CR\$"
assertGrep --matches=1 http.headers$n "^Serval-Rhizome-Bundle-Filehash: ${HASH[$n]}$CR\$"
assertGrep --matches=1 http.headers$n "^Serval-Rhizome-Bundle-BK: ${BK[$n]}$CR\$"
assertGrep --matches=1 http.headers$n "^Serval-Rhizome-Bundle-Date: ${DATE[$n]}$CR\$"
assertGrep --matches=1 http.headers$n "^Serval-Rhizome-Bundle-Name: \"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\$"
}
doc_RhizomeManifest="Fetch Rhizome bundle manifest"
setup_RhizomeManifest() {
setup
@ -315,24 +331,29 @@ test_RhizomeManifest() {
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\$"
assert_http_response_headers $n
done
}
doc_RhizomePayloadRaw="Fetch Rhizome raw payload"
setup_RhizomePayloadRaw() {
setup
add_bundles 0 2
}
test_RhizomePayloadRaw() {
:
for n in 0 1 2; do
executeOk curl \
--silent --fail --show-error \
--output raw.bin$n \
--dump-header http.headers$n \
--basic --user harry:potter \
"http://$addr_localhost:$PORTA/restful/rhizome/${BID[$n]}/raw.bin"
tfw_cat http.headers$n raw.bin$n
done
for n in 0 1 2; do
assert cmp file$n raw.bin$n
assert_http_response_headers $n
done
}
doc_RhizomePayloadDecrypted="Fetch Rhizome decrypted payload"