Rhizome Java API: improved form-data headers

Change manifest Content-Type from rhizome-manifest/text to
rhizome/manifest; format="text+binarysig"

Add "Content-Transfer-Encoding" form-part headers to Java API
sent form parts, although not currently checked by Rhizome
RESTful interface
This commit is contained in:
Andrew Bettison 2014-07-10 21:12:40 +09:30
parent 57cce64b6c
commit 04b2a20e54
6 changed files with 68 additions and 24 deletions

View File

@ -637,6 +637,17 @@ static int _parse_content_type(struct http_request *r, struct mime_content_type
continue; continue;
} }
r->cursor = start; r->cursor = start;
if (_skip_literal(r, "format=")) {
size_t n = _parse_token_or_quoted_string(r, ct->format, sizeof ct->format);
if (n == 0)
return 0;
if (n >= sizeof ct->format) {
WARNF("HTTP Content-Type format truncated: %s", alloca_str_toprint(ct->format));
return 0;
}
continue;
}
r->cursor = start;
struct substring param; struct substring param;
if (_skip_token(r, &param) && _skip_literal(r, "=") && _parse_token_or_quoted_string(r, NULL, 0)) { if (_skip_token(r, &param) && _skip_literal(r, "=") && _parse_token_or_quoted_string(r, NULL, 0)) {
if (r->debug_flag && *r->debug_flag) if (r->debug_flag && *r->debug_flag)
@ -1337,11 +1348,10 @@ static int http_request_parse_body_form_data(struct http_request *r)
char labelstr[labellen + 1]; char labelstr[labellen + 1];
strncpy(labelstr, label.start, labellen)[labellen] = '\0'; strncpy(labelstr, label.start, labellen)[labellen] = '\0';
str_tolower_inplace(labelstr); str_tolower_inplace(labelstr);
const char *value = r->cursor;
if (strcmp(labelstr, "content-length") == 0) { if (strcmp(labelstr, "content-length") == 0) {
if (r->part_header.content_length != CONTENT_LENGTH_UNKNOWN) { if (r->part_header.content_length != CONTENT_LENGTH_UNKNOWN) {
if (r->debug_flag && *r->debug_flag) if (r->debug_flag && *r->debug_flag)
DEBUGF("Skipping duplicate HTTP multipart header Content-Length: %s", alloca_toprint(50, sol, r->end - sol)); DEBUGF("Skipping duplicate HTTP multipart header %s", alloca_toprint(50, sol, r->end - sol));
return 400; return 400;
} }
http_size_t length; http_size_t length;
@ -1357,7 +1367,7 @@ static int http_request_parse_body_form_data(struct http_request *r)
else if (strcmp(labelstr, "content-type") == 0) { else if (strcmp(labelstr, "content-type") == 0) {
if (r->part_header.content_type.type[0]) { if (r->part_header.content_type.type[0]) {
if (r->debug_flag && *r->debug_flag) if (r->debug_flag && *r->debug_flag)
DEBUGF("Skipping duplicate HTTP multipart header Content-Type: %s", alloca_toprint(50, sol, r->end - sol)); DEBUGF("Skipping duplicate HTTP multipart header %s", alloca_toprint(50, sol, r->end - sol));
return 400; return 400;
} }
if (_parse_content_type(r, &r->part_header.content_type) && _skip_optional_space(r) && _skip_crlf(r)) { if (_parse_content_type(r, &r->part_header.content_type) && _skip_optional_space(r) && _skip_crlf(r)) {
@ -1371,7 +1381,7 @@ static int http_request_parse_body_form_data(struct http_request *r)
else if (strcmp(labelstr, "content-disposition") == 0) { else if (strcmp(labelstr, "content-disposition") == 0) {
if (r->part_header.content_disposition.type[0]) { if (r->part_header.content_disposition.type[0]) {
if (r->debug_flag && *r->debug_flag) if (r->debug_flag && *r->debug_flag)
DEBUGF("Skipping duplicate HTTP multipart header Content-Disposition: %s", alloca_toprint(50, sol, r->end - sol)); DEBUGF("Skipping duplicate HTTP multipart header %s", alloca_toprint(50, sol, r->end - sol));
return 400; return 400;
} }
if (_parse_content_disposition(r, &r->part_header.content_disposition) && _skip_optional_space(r) && _skip_crlf(r)) { if (_parse_content_disposition(r, &r->part_header.content_disposition) && _skip_optional_space(r) && _skip_crlf(r)) {
@ -1385,7 +1395,7 @@ static int http_request_parse_body_form_data(struct http_request *r)
else if (_skip_to_crlf(r)) { else if (_skip_to_crlf(r)) {
_commit(r); _commit(r);
if (r->debug_flag && *r->debug_flag) if (r->debug_flag && *r->debug_flag)
DEBUGF("Skip HTTP multipart header: %s: %s", alloca_str_toprint(labelstr), alloca_toprint(-1, value, value - r->cursor)); DEBUGF("Skip HTTP multipart header: %s", alloca_toprint(50, sol, r->parsed - sol));
return 0; return 0;
} }
} }

View File

@ -68,6 +68,7 @@ struct mime_content_type {
char subtype[64]; char subtype[64];
char multipart_boundary[71]; char multipart_boundary[71];
char charset[31]; char charset[31];
char format[31];
}; };
struct http_client_authorization { struct http_client_authorization {

View File

@ -373,12 +373,15 @@ public class RhizomeCommon
if (author != null) { if (author != null) {
wr.print("\r\n--" + boundary + "\r\n"); wr.print("\r\n--" + boundary + "\r\n");
wr.print("Content-Disposition: form-data; name=\"bundle-author\"\r\n"); wr.print("Content-Disposition: form-data; name=\"bundle-author\"\r\n");
wr.print("Content-Type: serval-mesh/sid\r\n");
wr.print("Content-Transfer-Encoding: hex\r\n");
wr.print("\r\n"); wr.print("\r\n");
wr.print(author.toHex()); wr.print(author.toHex());
} }
wr.print("\r\n--" + boundary + "\r\n"); wr.print("\r\n--" + boundary + "\r\n");
wr.print("Content-Disposition: form-data; name=\"manifest\"\r\n"); wr.print("Content-Disposition: form-data; name=\"manifest\"\r\n");
wr.print("Content-Type: rhizome-manifest/text\r\n"); wr.print("Content-Type: rhizome/manifest; format=\"text+binarysig\"\r\n");
wr.print("Content-Transfer-Encoding: binary\r\n");
wr.print("\r\n"); wr.print("\r\n");
wr.flush(); wr.flush();
manifest.toTextFormat(ost); manifest.toTextFormat(ost);
@ -391,6 +394,7 @@ public class RhizomeCommon
} }
wr.print("\r\n"); wr.print("\r\n");
wr.print("Content-Type: application/octet-stream\r\n"); wr.print("Content-Type: application/octet-stream\r\n");
wr.print("Content-Transfer-Encoding: binary\r\n");
wr.print("\r\n"); wr.print("\r\n");
wr.flush(); wr.flush();
byte[] buffer = new byte[4096]; byte[] buffer = new byte[4096];

View File

@ -418,10 +418,12 @@ static int insert_mime_part_header(struct http_request *hr, const struct mime_pa
if (r->u.insert.received_manifest) if (r->u.insert.received_manifest)
return http_response_form_part(r, "Duplicate", PART_MANIFEST, NULL, 0); return http_response_form_part(r, "Duplicate", PART_MANIFEST, NULL, 0);
form_buf_malloc_init(&r->u.insert.manifest, MAX_MANIFEST_BYTES); form_buf_malloc_init(&r->u.insert.manifest, MAX_MANIFEST_BYTES);
if ( strcmp(h->content_type.type, "rhizome-manifest") != 0 if ( strcmp(h->content_type.type, "rhizome") != 0
|| strcmp(h->content_type.subtype, "text") != 0 || strcmp(h->content_type.subtype, "manifest") != 0
) )
return http_response_form_part(r, "Unsupported Content-Type in", PART_MANIFEST, NULL, 0); return http_response_form_part(r, "Unsupported Content-Type in", PART_MANIFEST, NULL, 0);
if (strcmp(h->content_type.format, "text+binarysig") != 0)
return http_response_form_part(r, "Unsupported rhizome/manifest format in", PART_MANIFEST, NULL, 0);
r->u.insert.current_part = PART_MANIFEST; r->u.insert.current_part = PART_MANIFEST;
} }
else if (strcmp(h->content_disposition.name, PART_PAYLOAD) == 0) { else if (strcmp(h->content_disposition.name, PART_PAYLOAD) == 0) {

View File

@ -813,6 +813,10 @@ strbuf strbuf_append_mime_content_type(strbuf sb, const struct mime_content_type
strbuf_puts(sb, "; boundary="); strbuf_puts(sb, "; boundary=");
strbuf_append_quoted_string(sb, ct->multipart_boundary); strbuf_append_quoted_string(sb, ct->multipart_boundary);
} }
if (ct->format) {
strbuf_puts(sb, "; format=");
strbuf_append_quoted_string(sb, ct->format);
}
return sb; return sb;
} }

View File

@ -515,7 +515,7 @@ test_RhizomeInsert() {
--dump-header http.header$n \ --dump-header http.header$n \
--basic --user harry:potter \ --basic --user harry:potter \
"${authorargs[@]}" \ "${authorargs[@]}" \
--form "manifest=@manifest$n;type=rhizome-manifest/text" \ --form "manifest=@manifest$n;type=rhizome/manifest;format=\"text+binarysig\"" \
--form "payload=@file$n${payload_filename[$n]:+;filename=\"${payload_filename[$n]}\"}" \ --form "payload=@file$n${payload_filename[$n]:+;filename=\"${payload_filename[$n]}\"}" \
"http://$addr_localhost:$PORTA/restful/rhizome/insert" "http://$addr_localhost:$PORTA/restful/rhizome/insert"
tfw_cat http.header$n file$n.manifest tfw_cat http.header$n file$n.manifest
@ -579,7 +579,7 @@ test_RhizomeInsert() {
--output nfile$n.manifest \ --output nfile$n.manifest \
--dump-header http.headers$n \ --dump-header http.headers$n \
--basic --user harry:potter \ --basic --user harry:potter \
--form "manifest=@nmanifest$n;type=rhizome-manifest/text" \ --form "manifest=@nmanifest$n;type=rhizome/manifest;format=\"text+binarysig\"" \
--form "payload=@nfile$n;filename=\"nfile$n\"" \ --form "payload=@nfile$n;filename=\"nfile$n\"" \
"http://$addr_localhost:$PORTA/restful/rhizome/insert" "http://$addr_localhost:$PORTA/restful/rhizome/insert"
tfw_cat http.headers$n nfile$n.manifest tfw_cat http.headers$n nfile$n.manifest
@ -616,7 +616,7 @@ test_RhizomeInsertAnon() {
--dump-header http.header \ --dump-header http.header \
--basic --user harry:potter \ --basic --user harry:potter \
--form "bundle-secret=$SECRET" \ --form "bundle-secret=$SECRET" \
--form "manifest=@file2.manifest;type=rhizome-manifest/text" \ --form "manifest=@file2.manifest;type=rhizome/manifest;format=\"text+binarysig\"" \
--form "payload=@file2" \ --form "payload=@file2" \
"http://$addr_localhost:$PORTA/restful/rhizome/insert" "http://$addr_localhost:$PORTA/restful/rhizome/insert"
tfw_cat http.header ifile2.manifest tfw_cat http.header ifile2.manifest
@ -642,7 +642,7 @@ test_RhizomeInsertEmpty() {
--output empty.manifest \ --output empty.manifest \
--dump-header http.header \ --dump-header http.header \
--basic --user harry:potter \ --basic --user harry:potter \
--form "manifest=;type=rhizome-manifest/text" \ --form "manifest=;type=rhizome/manifest;format=\"text+binarysig\"" \
--form "payload=@empty;filename=\"lucky\"" \ --form "payload=@empty;filename=\"lucky\"" \
"http://$addr_localhost:$PORTA/restful/rhizome/insert" "http://$addr_localhost:$PORTA/restful/rhizome/insert"
tfw_cat http.header empty.manifest tfw_cat http.header empty.manifest
@ -671,7 +671,7 @@ test_RhizomeInsertLarge() {
--output file1.manifest \ --output file1.manifest \
--dump-header http.header \ --dump-header http.header \
--basic --user harry:potter \ --basic --user harry:potter \
--form "manifest=;type=rhizome-manifest/text" \ --form "manifest=;type=rhizome/manifest;format=\"text+binarysig\"" \
--form "payload=@file1" \ --form "payload=@file1" \
"http://$addr_localhost:$PORTA/restful/rhizome/insert" "http://$addr_localhost:$PORTA/restful/rhizome/insert"
tfw_cat http.header -v file1.manifest tfw_cat http.header -v file1.manifest
@ -722,7 +722,7 @@ test_RhizomeInsertIncorrectManifestType() {
--output http.body \ --output http.body \
--dump-header http.header \ --dump-header http.header \
--basic --user harry:potter \ --basic --user harry:potter \
--form "manifest=;type=rhizome-manifest/something" \ --form "manifest=;type=rhizome-manifest/text" \
--form "payload=@file1" \ --form "payload=@file1" \
"http://$addr_localhost:$PORTA/restful/rhizome/insert" "http://$addr_localhost:$PORTA/restful/rhizome/insert"
tfw_cat http.header http.body tfw_cat http.header http.body
@ -734,6 +734,29 @@ test_RhizomeInsertIncorrectManifestType() {
assert_rhizome_list assert_rhizome_list
} }
doc_RhizomeInsertIncorrectManifestFormat="HTTP RESTful insert Rhizome bundle, incorrect 'manifest' content format"
setup_RhizomeInsertIncorrectManifestFormat() {
setup
echo 'File one' >file1
}
test_RhizomeInsertIncorrectManifestFormat() {
execute curl \
--silent --show-error --write-out '%{http_code}' \
--output http.body \
--dump-header http.header \
--basic --user harry:potter \
--form "manifest=;type=rhizome/manifest;format=\"text\"" \
--form "payload=@file1" \
"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})'
assertJqGrep --ignore-case http.body '.http_status_message' 'unsupported.*format.*manifest.*form.*part'
executeOk_servald rhizome list
assert_rhizome_list
}
doc_RhizomeInsertDuplicateManifest="HTTP RESTful insert Rhizome bundle, duplicate 'manifest' form part" doc_RhizomeInsertDuplicateManifest="HTTP RESTful insert Rhizome bundle, duplicate 'manifest' form part"
setup_RhizomeInsertDuplicateManifest() { setup_RhizomeInsertDuplicateManifest() {
setup setup
@ -747,8 +770,8 @@ test_RhizomeInsertDuplicateManifest() {
--output http.body \ --output http.body \
--dump-header http.header \ --dump-header http.header \
--basic --user harry:potter \ --basic --user harry:potter \
--form "manifest=@file1.manifest;type=rhizome-manifest/text" \ --form "manifest=@file1.manifest;type=rhizome/manifest;format=\"text+binarysig\"" \
--form "manifest=@file2.manifest;type=rhizome-manifest/text" \ --form "manifest=@file2.manifest;type=rhizome/manifest;format=\"text+binarysig\"" \
--form "payload=@file1" \ --form "payload=@file1" \
"http://$addr_localhost:$PORTA/restful/rhizome/insert" "http://$addr_localhost:$PORTA/restful/rhizome/insert"
tfw_cat http.header http.body tfw_cat http.header http.body
@ -772,7 +795,7 @@ test_RhizomeInsertJournal() {
--output http.body \ --output http.body \
--dump-header http.header \ --dump-header http.header \
--basic --user harry:potter \ --basic --user harry:potter \
--form "manifest=@file1.manifest;type=rhizome-manifest/text" \ --form "manifest=@file1.manifest;type=rhizome/manifest;format=\"text+binarysig\"" \
--form "payload=@file1" \ --form "payload=@file1" \
"http://$addr_localhost:$PORTA/restful/rhizome/insert" "http://$addr_localhost:$PORTA/restful/rhizome/insert"
tfw_cat http.header http.body tfw_cat http.header http.body
@ -796,7 +819,7 @@ test_RhizomeInsertMissingPayload() {
--output http.body \ --output http.body \
--dump-header http.header \ --dump-header http.header \
--basic --user harry:potter \ --basic --user harry:potter \
--form "manifest=@file1.manifest;type=rhizome-manifest/text" \ --form "manifest=@file1.manifest;type=rhizome/manifest;format=\"text+binarysig\"" \
"http://$addr_localhost:$PORTA/restful/rhizome/insert" "http://$addr_localhost:$PORTA/restful/rhizome/insert"
tfw_cat http.header http.body tfw_cat http.header http.body
assertExitStatus == 0 assertExitStatus == 0
@ -820,7 +843,7 @@ test_RhizomeInsertDuplicatePayload() {
--output http.body \ --output http.body \
--dump-header http.header \ --dump-header http.header \
--basic --user harry:potter \ --basic --user harry:potter \
--form "manifest=@file1.manifest;type=rhizome-manifest/text" \ --form "manifest=@file1.manifest;type=rhizome/manifest;format=\"text+binarysig\"" \
--form "payload=@file1" \ --form "payload=@file1" \
--form "payload=@file2" \ --form "payload=@file2" \
"http://$addr_localhost:$PORTA/restful/rhizome/insert" "http://$addr_localhost:$PORTA/restful/rhizome/insert"
@ -846,7 +869,7 @@ test_RhizomeInsertPartOrder() {
--dump-header http.header \ --dump-header http.header \
--basic --user harry:potter \ --basic --user harry:potter \
--form "payload=@file1" \ --form "payload=@file1" \
--form "manifest=@file1.manifest;type=rhizome-manifest/text" \ --form "manifest=@file1.manifest;type=rhizome/manifest;format=\"text+binarysig\"" \
"http://$addr_localhost:$PORTA/restful/rhizome/insert" "http://$addr_localhost:$PORTA/restful/rhizome/insert"
tfw_cat http.header http.body tfw_cat http.header http.body
assertExitStatus == 0 assertExitStatus == 0
@ -869,7 +892,7 @@ test_RhizomeInsertPartUnsupported() {
--output http.body \ --output http.body \
--dump-header http.header \ --dump-header http.header \
--basic --user harry:potter \ --basic --user harry:potter \
--form "manifest=@file1.manifest;type=rhizome-manifest/text" \ --form "manifest=@file1.manifest;type=rhizome/manifest;format=\"text+binarysig\"" \
--form "payload=@file1" \ --form "payload=@file1" \
--form "happyhappy=joyjoy" \ --form "happyhappy=joyjoy" \
"http://$addr_localhost:$PORTA/restful/rhizome/insert" "http://$addr_localhost:$PORTA/restful/rhizome/insert"
@ -897,7 +920,7 @@ test_RhizomeInsertIncorrectFilesize() {
--output http.body \ --output http.body \
--dump-header http.header \ --dump-header http.header \
--basic --user harry:potter \ --basic --user harry:potter \
--form "manifest=@file1.manifest;type=rhizome-manifest/text" \ --form "manifest=@file1.manifest;type=rhizome/manifest;format=\"text+binarysig\"" \
--form "payload=@file1" \ --form "payload=@file1" \
"http://$addr_localhost:$PORTA/restful/rhizome/insert" "http://$addr_localhost:$PORTA/restful/rhizome/insert"
tfw_cat http.header http.body tfw_cat http.header http.body
@ -911,7 +934,7 @@ test_RhizomeInsertIncorrectFilesize() {
--output http.body \ --output http.body \
--dump-header http.header \ --dump-header http.header \
--basic --user harry:potter \ --basic --user harry:potter \
--form "manifest=@file2.manifest;type=rhizome-manifest/text" \ --form "manifest=@file2.manifest;type=rhizome/manifest;format=\"text+binarysig\"" \
--form "payload=@file2" \ --form "payload=@file2" \
"http://$addr_localhost:$PORTA/restful/rhizome/insert" "http://$addr_localhost:$PORTA/restful/rhizome/insert"
tfw_cat http.header http.body tfw_cat http.header http.body
@ -936,7 +959,7 @@ test_RhizomeInsertIncorrectFilehash() {
--output http.body \ --output http.body \
--dump-header http.header \ --dump-header http.header \
--basic --user harry:potter \ --basic --user harry:potter \
--form "manifest=@file1.manifest;type=rhizome-manifest/text" \ --form "manifest=@file1.manifest;type=rhizome/manifest;format=\"text+binarysig\"" \
--form "payload=@file1" \ --form "payload=@file1" \
"http://$addr_localhost:$PORTA/restful/rhizome/insert" "http://$addr_localhost:$PORTA/restful/rhizome/insert"
tfw_cat http.header http.body tfw_cat http.header http.body