mirror of
https://github.com/servalproject/serval-dna.git
synced 2025-02-21 09:51:50 +00:00
MeshMS RESTful API stricter on incoming form data
/restful/meshms/SID/SID/sendmessage now enforces Content-Disposition: form-data (was ignoring), and enforces Content-Type: text/plain; charset=utf-8 (was ignoring) New negative test cases to ensure that these are treated strictly
This commit is contained in:
parent
533c0be445
commit
819b8dc9e7
33
httpd.c
33
httpd.c
@ -421,6 +421,39 @@ void form_buf_malloc_release(struct form_buf_malloc *f)
|
||||
f->size_limit = 0;
|
||||
}
|
||||
|
||||
int http_response_content_type(httpd_request *r, const char *what, const struct mime_content_type *ct)
|
||||
{
|
||||
if (config.debug.httpd)
|
||||
DEBUGF("%s Content-Type: %s/%s%s%s%s%s", what, ct->type, ct->subtype,
|
||||
ct->charset[0] ? "; charset=" : "",
|
||||
ct->charset,
|
||||
ct->multipart_boundary[0] ? "; boundary=" : "",
|
||||
ct->multipart_boundary
|
||||
);
|
||||
strbuf msg = strbuf_alloca(200);
|
||||
strbuf_sprintf(msg, "%s Content-Type:", what);
|
||||
if (ct->type[0])
|
||||
strbuf_sprintf(msg, " %s", ct->type);
|
||||
if (ct->subtype[0])
|
||||
strbuf_sprintf(msg, "/%s", ct->subtype);
|
||||
if (ct->charset[0])
|
||||
strbuf_sprintf(msg, "; charset=%s", ct->charset);
|
||||
if (ct->multipart_boundary[0])
|
||||
strbuf_sprintf(msg, "; boundary=%s", ct->multipart_boundary);
|
||||
http_request_simple_response(&r->http, 403, strbuf_str(msg));
|
||||
return 403;
|
||||
}
|
||||
|
||||
int http_response_content_disposition(httpd_request *r, const char *what, const char *type)
|
||||
{
|
||||
if (config.debug.httpd)
|
||||
DEBUGF("%s Content-Disposition: %s %s", what, type);
|
||||
strbuf msg = strbuf_alloca(100);
|
||||
strbuf_sprintf(msg, "%s Content-Disposition: %s", what, type);
|
||||
http_request_simple_response(&r->http, 403, strbuf_str(msg));
|
||||
return 403;
|
||||
}
|
||||
|
||||
int http_response_form_part(httpd_request *r, const char *what, const char *partname, const char *text, size_t textlen)
|
||||
{
|
||||
if (config.debug.httpd)
|
||||
|
2
httpd.h
2
httpd.h
@ -192,6 +192,8 @@ typedef int HTTP_HANDLER(httpd_request *r, const char *remainder);
|
||||
|
||||
int is_http_header_complete(const char *buf, size_t len, size_t read_since_last_call);
|
||||
int authorize(struct http_request *r);
|
||||
int http_response_content_type(httpd_request *r, const char *what, const struct mime_content_type *ct);
|
||||
int http_response_content_disposition(httpd_request *r, const char *what, const char *type);
|
||||
int http_response_form_part(httpd_request *r, const char *what, const char *partname, const char *text, size_t textlen);
|
||||
int accumulate_text(httpd_request *r, const char *partname, char *textbuf, size_t textsiz, size_t *textlenp, const char *buf, size_t len);
|
||||
|
||||
|
@ -523,6 +523,8 @@ static int send_mime_part_end(struct http_request *hr)
|
||||
static int send_mime_part_header(struct http_request *hr, const struct mime_part_headers *h)
|
||||
{
|
||||
httpd_request *r = (httpd_request *) hr;
|
||||
if (strcmp(h->content_disposition.type, "form-data") != 0)
|
||||
return http_response_content_disposition(r, "Unsupported", h->content_disposition.type);
|
||||
if (strcmp(h->content_disposition.name, PART_MESSAGE) == 0) {
|
||||
if (r->u.sendmsg.received_message)
|
||||
return http_response_form_part(r, "Duplicate", PART_MESSAGE, NULL, 0);
|
||||
@ -531,6 +533,14 @@ static int send_mime_part_header(struct http_request *hr, const struct mime_part
|
||||
}
|
||||
else
|
||||
return http_response_form_part(r, "Unsupported", h->content_disposition.name, NULL, 0);
|
||||
if (!h->content_type.type[0] || !h->content_type.subtype[0])
|
||||
return http_response_content_type(r, "Missing", &h->content_type);
|
||||
if (strcmp(h->content_type.type, "text") != 0 || strcmp(h->content_type.subtype, "plain") != 0)
|
||||
return http_response_content_type(r, "Unsupported", &h->content_type);
|
||||
if (!h->content_type.charset[0])
|
||||
return http_response_content_type(r, "Missing charset", &h->content_type);
|
||||
if (strcmp(h->content_type.charset, "utf-8") != 0)
|
||||
return http_response_content_type(r, "Unsupported charset", &h->content_type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -313,6 +313,8 @@ static int insert_make_manifest(httpd_request *r)
|
||||
static int insert_mime_part_header(struct http_request *hr, const struct mime_part_headers *h)
|
||||
{
|
||||
httpd_request *r = (httpd_request *) hr;
|
||||
if (strcmp(h->content_disposition.type, "form-data") != 0)
|
||||
return http_response_content_disposition(r, "Unsupported", h->content_disposition.type);
|
||||
if (strcmp(h->content_disposition.name, PART_AUTHOR) == 0) {
|
||||
if (r->u.insert.received_author)
|
||||
return http_response_form_part(r, "Duplicate", PART_AUTHOR, NULL, 0);
|
||||
|
@ -1190,7 +1190,7 @@ test_MeshmsSend() {
|
||||
--silent --fail --show-error \
|
||||
--output sendmessage.json \
|
||||
--basic --user harry:potter \
|
||||
--form "message=Hello World" \
|
||||
--form "message=Hello World;type=text/plain;charset=utf-8" \
|
||||
"http://$addr_localhost:$PORTA/restful/meshms/$SIDA1/$SIDA2/sendmessage"
|
||||
executeOk_servald meshms list messages $SIDA1 $SIDA2
|
||||
assertStdoutGrep --matches=1 ':>:Hello World'
|
||||
@ -1198,14 +1198,14 @@ test_MeshmsSend() {
|
||||
--silent --fail --show-error \
|
||||
--output sendmessage.json \
|
||||
--basic --user ron:weasley \
|
||||
--form "message=Hello back!" \
|
||||
--form "message=Hello back!;type=text/plain;charset=utf-8" \
|
||||
"http://$addr_localhost:$PORTA/restful/meshms/$SIDA2/$SIDA1/sendmessage"
|
||||
executeOk_servald meshms list messages $SIDA1 $SIDA2
|
||||
assertStdoutGrep --matches=1 ':>:Hello World$'
|
||||
assertStdoutGrep --matches=1 ':<:Hello back!$'
|
||||
}
|
||||
|
||||
doc_MeshmsSendMissingMessage="HTTP RESTful MeshMS send missing 'message' form part "
|
||||
doc_MeshmsSendMissingMessage="HTTP RESTful MeshMS send missing 'message' form part"
|
||||
setup_MeshmsSendMissingMessage() {
|
||||
IDENTITY_COUNT=2
|
||||
setup
|
||||
@ -1227,7 +1227,7 @@ test_MeshmsSendMissingMessage() {
|
||||
assertStdoutLineCount '==' 2
|
||||
}
|
||||
|
||||
doc_MeshmsSendDuplicateMessage="HTTP RESTful MeshMS send missing 'message' form part "
|
||||
doc_MeshmsSendDuplicateMessage="HTTP RESTful MeshMS send duplicate 'message' form parts"
|
||||
setup_MeshmsSendDuplicateMessage() {
|
||||
IDENTITY_COUNT=2
|
||||
setup
|
||||
@ -1238,8 +1238,8 @@ test_MeshmsSendDuplicateMessage() {
|
||||
--output http.body \
|
||||
--dump-header http.header \
|
||||
--basic --user harry:potter \
|
||||
--form "message=Hello one" \
|
||||
--form "message=Hello two" \
|
||||
--form "message=Hello one;type=text/plain;charset=utf-8" \
|
||||
--form "message=Hello two;type=text/plain;charset=utf-8" \
|
||||
"http://$addr_localhost:$PORTA/restful/meshms/$SIDA2/$SIDA1/sendmessage"
|
||||
tfw_cat http.header http.body
|
||||
assertExitStatus == 0
|
||||
@ -1250,6 +1250,94 @@ test_MeshmsSendDuplicateMessage() {
|
||||
assertStdoutLineCount '==' 2
|
||||
}
|
||||
|
||||
doc_MeshmsSendMessageMissingContentType="HTTP RESTful MeshMS send 'message' form part missing Content-Type"
|
||||
setup_MeshmsSendMessageMissingContentType() {
|
||||
IDENTITY_COUNT=2
|
||||
setup
|
||||
}
|
||||
test_MeshmsSendMessageMissingContentType() {
|
||||
execute curl \
|
||||
--silent --show-error --write-out '%{http_code}' \
|
||||
--output http.body \
|
||||
--dump-header http.header \
|
||||
--basic --user harry:potter \
|
||||
--form "message=Hello there" \
|
||||
"http://$addr_localhost:$PORTA/restful/meshms/$SIDA2/$SIDA1/sendmessage"
|
||||
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' 'missing.*content.*type'
|
||||
executeOk_servald meshms list messages $SIDA1 $SIDA2
|
||||
assertStdoutLineCount '==' 2
|
||||
}
|
||||
|
||||
doc_MeshmsSendMessageUnsupportedContentType="HTTP RESTful MeshMS send 'message' form part unsupported Content-Type"
|
||||
setup_MeshmsSendMessageUnsupportedContentType() {
|
||||
IDENTITY_COUNT=2
|
||||
setup
|
||||
}
|
||||
test_MeshmsSendMessageUnsupportedContentType() {
|
||||
execute curl \
|
||||
--silent --show-error --write-out '%{http_code}' \
|
||||
--output http.body \
|
||||
--dump-header http.header \
|
||||
--basic --user harry:potter \
|
||||
--form "message=Hello there;type=text/rich" \
|
||||
"http://$addr_localhost:$PORTA/restful/meshms/$SIDA2/$SIDA1/sendmessage"
|
||||
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.*content.*type'
|
||||
executeOk_servald meshms list messages $SIDA1 $SIDA2
|
||||
assertStdoutLineCount '==' 2
|
||||
}
|
||||
|
||||
doc_MeshmsSendMessageMissingCharset="HTTP RESTful MeshMS send 'message' form part missing charset"
|
||||
setup_MeshmsSendMessageMissingCharset() {
|
||||
IDENTITY_COUNT=2
|
||||
setup
|
||||
}
|
||||
test_MeshmsSendMessageMissingCharset() {
|
||||
execute curl \
|
||||
--silent --show-error --write-out '%{http_code}' \
|
||||
--output http.body \
|
||||
--dump-header http.header \
|
||||
--basic --user harry:potter \
|
||||
--form "message=Hello there;type=text/plain" \
|
||||
"http://$addr_localhost:$PORTA/restful/meshms/$SIDA2/$SIDA1/sendmessage"
|
||||
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' 'missing.*charset'
|
||||
executeOk_servald meshms list messages $SIDA1 $SIDA2
|
||||
assertStdoutLineCount '==' 2
|
||||
}
|
||||
|
||||
doc_MeshmsSendMessageUnsupportedCharset="HTTP RESTful MeshMS send 'message' form part unsupported charset"
|
||||
setup_MeshmsSendMessageUnsupportedCharset() {
|
||||
IDENTITY_COUNT=2
|
||||
setup
|
||||
}
|
||||
test_MeshmsSendMessageUnsupportedCharset() {
|
||||
execute curl \
|
||||
--silent --show-error --write-out '%{http_code}' \
|
||||
--output http.body \
|
||||
--dump-header http.header \
|
||||
--basic --user harry:potter \
|
||||
--form "message=Hello there;type=text/plain;charset=latin-1" \
|
||||
"http://$addr_localhost:$PORTA/restful/meshms/$SIDA2/$SIDA1/sendmessage"
|
||||
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.*charset'
|
||||
executeOk_servald meshms list messages $SIDA1 $SIDA2
|
||||
assertStdoutLineCount '==' 2
|
||||
}
|
||||
|
||||
doc_MeshmsSendNoIdentity="HTTP RESTful MeshMS send from unknown identity"
|
||||
setup_MeshmsSendNoIdentity() {
|
||||
setup
|
||||
@ -1261,7 +1349,7 @@ test_MeshmsSendNoIdentity() {
|
||||
--output http.body \
|
||||
--dump-header http.header \
|
||||
--basic --user harry:potter \
|
||||
--form "message=Hello" \
|
||||
--form "message=Hello;type=text/plain;charset=utf-8" \
|
||||
"http://$addr_localhost:$PORTA/restful/meshms/$SIDX/$SIDA/sendmessage"
|
||||
tfw_cat http.header http.body
|
||||
assertExitStatus == 0
|
||||
|
Loading…
x
Reference in New Issue
Block a user