servalproject / serval-dna

The Serval Project's core daemon that implements Distributed Numbering Architecture (DNA), MDP, VoMP, Rhizome, MeshMS, etc.
http://servalproject.org
Other
171 stars 80 forks source link

servald's http_server requires multipart/form-data for POST requests #82

Closed TobiasWooldridge closed 6 years ago

TobiasWooldridge commented 10 years ago

servald seems to outright block every HTTP POST request which doesn't specify the following header

 Content-Type: multipart/form-data

This doesn't really make sense unless you're sending files or a large amount of text to the server, and makes it difficult to use the API with most AJAX libraries and older browsers.

The following Content-Types should be supported because they are generally more appropriate and easier to use:

Content-Type: text/plain
Content-Type: text/plain;charset=UTF-8 # charsets may be specified here
Content-Type: application/x-www-form-urlencoded
TobiasWooldridge commented 10 years ago

multipart/form-data may also not work either

Sending a POST request using the JS

var username = 'demouser';
var password = 'demopassword';
var data = { message : "Hello world" };
var address = "http://localhost:4110/restful/meshms/CD657569C180692BA8073F9CE98F43603143B7F6C2C2E94E2980E710418FA711/CDC40A331EFF282ACB96CD8A00F68A2502F7A0EF2053EDA0A919FC4D5976E870/sendmessage";

var params = new FormData();
for (var key in data) {
    if (data.hasOwnProperty(key)) {
        params.append(key, data[key]);
    }
}

xhr.open("POST", address, true);
xhr.setRequestHeader('Authorization', 'Basic ' + btoa(username + ":" + password));
xhr.send(params);

Generates a request with the following headers

Accept  text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding gzip, deflate
Accept-Language en-gb,en;q=0.5
Authorization   Basic ZGVtb3VzZXI6ZGVtb3Bhc3N3b3Jk
Cache-Control   no-cache
Connection  keep-alive
Content-Length  180
Content-Type    multipart/form-data; boundary=---------------------------134289594921465685201799329687
Host    localhost:4110
Origin  http://localhost:8080
Pragma  no-cache
Referer http://localhost:8080/
User-Agent  Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:30.0) Gecko/20100101 Firefox/30.0

Which inexplicably gets the following error message

{
 "http_status_code": 403,
 "http_status_message": "Missing Content-Type:"
}
lakeman commented 10 years ago

You just need to be more specific about the content type. This works for me;

params.append("message", new Blob(["Hello world"], {type: "text/plain; charset=utf-8"}));
TobiasWooldridge commented 10 years ago

This seems to work, thanks

I'm hesitant to close this issue because this is an undocumented, unexpected restriction without an error message

quixotique commented 10 years ago

The missing Content-Type in the status message refers to the form part, not the request header. Each form part must specify its own content type.

As for the other content types you suggest we support, requests that take only a single, potentially large parameter, text/plain with a charset would certainly be suitable for text data, and application/octer-stream would be suitable for opaque binary data. All the requests we have implemented so far take more than one large parameter, so a multipart content must be used. At the moment we have only implemented multipart/form-data. It would certainly be possible to also implement application/x-www-form-urlencoded but this involves more encoding/decoding of the data stream, so we didn't choose it.

Forcing clients to explicitly specify the content type of all their supplied data forces developers to confront and deal with the issues of data format and encoding instead of simply hacking ahead using assumed defaults, and unwittingly creating injection-type bugs when the data stream violates the encapsulation rules of the default content type.

TobiasWooldridge commented 10 years ago

While I understand and appreciate your reasoning, I think it should be documented that only a subset of RFC 1867 has been implemented, because it is not expected behavior

lakeman commented 10 years ago

Trying to research this a little more, it seems that browsers prefer to leave out the content type and charset, defaulting to text/plain & 7bit us-ascii. Since we want to support full unicode, I think we've made the right decision to force the client to be specific.

And yes, we need to improve our documentation of this area. I suggest we start working on a Javascript library that provides helper functions for building each restful request.

quixotique commented 10 years ago

If we ever support the default of text/plain; charset=us-ascii (see http://tools.ietf.org/html/rfc2046#section-4.1.2 and http://tools.ietf.org/html/rfc2045#section-5.2), then the server must check that all the content has bit 8 zero before accepting it.

quixotique commented 6 years ago

The supported REST API Content-Types are now documented in REST-API.md, and the individual API documentation, eg, REST-API-Rhizome.md is comprehensive and explicit about how to format requests.