It seems when adding content data to the request body in a POST command, DataSnap server insists that this data is always JSON. This is why when using TStream as an input parameter, the stream data is converted to a JSON array of integers (bytes) by the Delphi DataSnap client. This format is very size inefficient as with upto 3 digits per byte, plus the comma, the size of the data being uploaded can grow by as much as 4 times.
What I have therefore done instead is to encode the data to upload in Base64. My server method now looks like this :
function TServerMethods.updateUploadFile(sFilename: string; Base64Data: TJSONObject): string;
Notice I'm wrapping the Base64 string in a TJSONObject. This is because if you just specify a String type, the Delphi DataSnap client will call the method with a GET and attempt to put the whole Base64 string in the URL path, causing a 'Connection Closed Gracefully' error. Using a TJSONObject forces DataSnap to use a POST and put the data in the content body. The JSON object passed is a single pair object :
{"UploadedData":"JVBERi0xLjMNCiXi48B5SiWGTK3PaY.........."}
This way the size of the data uploaded is much smaller and faster to transfer. I'd still prefer to be able to stream the raw data in the content body but DataSnap doesn't allow this.