I have this Jersey-client POST request:
MultiPart multiPart = new MultiPart();
multiPart.bodyPart(new BodyPart(inParams.toString(), MediaType.TEXT_PLAIN_TYPE));
final File fileToUpload = new File(filePath);
multiPart.bodyPart(new BodyPart(fileToUpload, MediaType.MULTIPART_FORM_DATA_TYPE));
final ClientResponse clientResp = resource.type("multipart/form-data").post(ClientResponse.class, multiPart);
Is there way I can print the actual request, I expect to get something like :
----WebKitFormBoundaryE19zNvXGzXaLvS5C
Content-Disposition: form-data; name="Content"
{"SP_PROT_SENDER":"","SP_PROT_IN":"0","FILENAME":"testRest.rar"}
----WebKitFormBoundaryE19zNvXGzXaLvS5C
Content-Disposition: form-data; name="a"; filename="testRest.rar"
Content-Type:
(...)
----WebKitFormBoundaryE19zNvXGzXaLvS5C
You've probably already solved this, but I ran into this the other day and found that the easiest way was to sniff the posted traffic with Netcat.
Here's how:
Make the URL you're posting use some obscure port number not used by anything else, like 15734.
In another terminal window, type nc -kl 15734.
Trigger the request. The request will be printed in the above terminal window.
Things like GZip compression and chunking can make the output look weird, so you might want to turn those features off.
Related
I created a file upload functionality in Jersey.
#POST
#Path("/import")
#Consumes(MediaType.MULTIPART_FORM_DATA)
public static Response importFile(
#FormDataParam("file") InputStream fileInputStream,
#FormDataParam("file") FormDataContentDisposition fileMetaData,
When I send a file as multipart formdata from the browser (Firefox and Chrome) using Fetch API or a jQuery POST, Jersey responds with a org.jvnet.mimepull.MIMEParsingException: Missing start boundary.
This is apparently not due to the fact that e.g. Chrome uses a case-sensitive boundary, as others have had, since the issue happens in Firefox as well, which uses a numeric boundary.
It seems that in my case, the browser sends the boundary with two additional dashes before each boundary in the body and after the last one (which seems to be correct according to the multipart specification https://www.w3.org/Protocols/rfc1341/7_2_Multipart.html), but Jersey (2.25.1) / Mimepull (1.9.14) does not accept that.
Content-Type multipart/form-data; boundary=
---------------------------23978830417520517351040096390
-----------------------------23978830417520517351040096390
Content-Disposition: form-data; name="file"; filename="testdata.csv"
Content-Type: text/csv
<snip>
-----------------------------23978830417520517351040096390--
On the contrary, when I send my request using Postman, it encodes the boundary in the body without those two additional dashes and Jersey accepts the request.
POST /myapi/import HTTP/1.1
Content-Length: 708
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
----WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="file"; filename="testdata.csv"
Content-Type: text/csv
(data)
----WebKitFormBoundary7MA4YWxkTrZu0gW
<snip>
----WebKitFormBoundary7MA4YWxkTrZu0gW
What is the correct behaviour in this case and how is it possible to implement the file upload in a way that different clients can use it?
Is there an alternative to using multipart implementation for file uploads?
We need to send a multipart/form-data request containing two files. Since we had some issues with the requests, we set up a request bin page to try and analyze the requests themselves, since Postman seemed to work fine.
My second file is generated by a different service as a byte stream and represents a JSON object. This byte stream seems to have a NUL (0) byte terminator at the end.
If I add this second file to the multipart/form-data request, something like the following results:
With the body looking as follows:
--9ac41cec-a0ff-4afd-b687-6b8c2f1bddd6.
Content-Disposition: form-data; name="metadata"; filename="metadata-1584981615.json".
Content-Type: application/json.
Content-Length: 581.
.
{"...":"..."}.
--9ac41cec-a0ff-4afd-b687-6b8c2f1bddd6.
Content-Disposition: form-data; name="file"; filename="file-1584981615.json".
Content-Type: application/json.
Content-Length: 12205.
.
{"...":"..."}..
--9ac41cec-a0ff-4afd-b687-6b8c2f1bddd6--.
Obviously, this is supremely invalid. It seems that the multipart request is adding the . characters at the end of every line.
I was able to reproduce this behaviour with Spring Web 5.1.5.RELEASE, okHttp 3.14.7 and Apache HttpComponents 4.5.7. The behaviour does not seem to change if I remove the NUL (0) byte terminator from the byte stream.
Here's the odd part: the receiving webserver accepts this request as a valid multipart/form-data request.
For the record, here's what a valid request (that is also accepted by the webserver) looks like from request bin's point of view (different file):
--83611e7f-ad57-4893-9d1b-5ba2c4543d2a
Content-Disposition: form-data; name="metadata"; filename="metadata-1584982345.json"
Content-Type: application/json
Content-Length: 895
{"...": "..."}
--83611e7f-ad57-4893-9d1b-5ba2c4543d2a
Content-Disposition: form-data; name="file"; filename="file-1584982345.json"
Content-Type: application/json
Content-Length: 9868
{"...": "..."}
--83611e7f-ad57-4893-9d1b-5ba2c4543d2a--
Aside from having the explicit terminator at the end (which does not seem to make a difference at all), the byte stream does not look broken. new String(bytes) gives a valid JSON object. So I'm thinking it has to be something else.
Has anyone encountered this issue before? I'm unsure how to proceed with debugging this issue, and I'm fairly certain that sending improper requests, even though they might be accepted by the remote server at this time, almost certainly guarantees that my code will break somewhere along the line...
I need to receive an HTTP Post Multipart which contains only 2 parameters:
A JSON string
A binary file
Which is the correct way to set the body?
I'm going to test the HTTP call using Chrome REST console, so I'm wondering if the correct solution is to set a "label" key for the JSON parameter and the binary file.
On the server side I'm using Resteasy 2.x, and I'm going to read the Multipart body like this:
#POST
#Consumes("multipart/form-data")
public String postWithPhoto(MultipartFormDataInput multiPart) {
Map <String, List<InputPart>> params = multiPart.getFormDataMap();
String myJson = params.get("myJsonName").get(0).getBodyAsString();
InputPart imagePart = params.get("photo").get(0);
//do whatever I need to do with my json and my photo
}
Is this the way to go?
Is it correct to retrieve my JSON string using the key "myJsonName" that identify that particular content-disposition?
Are there any other way to receive these 2 content in one HTTP multipart request?
If I understand you correctly, you want to compose a multipart request manually from an HTTP/REST console. The multipart format is simple; a brief introduction can be found in the HTML 4.01 spec. You need to come up with a boundary, which is a string not found in the content, let’s say HereGoes. You set request header Content-Type: multipart/form-data; boundary=HereGoes. Then this should be a valid request body:
--HereGoes
Content-Disposition: form-data; name="myJsonString"
Content-Type: application/json
{"foo": "bar"}
--HereGoes
Content-Disposition: form-data; name="photo"
Content-Type: image/jpeg
Content-Transfer-Encoding: base64
<...JPEG content in base64...>
--HereGoes--
I'm working on a REST resource that takes in a key and data (value) . I'd like to be robust so this data can be anything. It could range from a string to a file.
To handle this, I have the PUT REST method which is at the end of the post. Nothing fancy, just trying to PUT basic data. If I send data that is a string it works no problem.
However, if I try to send a file across, I get this error: org.jboss.resteasy.spi.UnsupportedMediaTypeException: Cannot consume content type. Here's why this doesn't make sense to me:
If I change the #Consumes from application/octet-stream to #Consumes("multipart/form-data"), I can send a file across just fine. When examining the file that's stored I see something like this:
------WebKitFormBoundaryfuQalizBHtg1BiLJ
Content-Disposition: form-data; name="fileUpload1"; filename="uploadedFile.extension"
Content-Type: application/octet-stream
/* file information here */
------WebKitFormBoundaryfuQalizBHtg1BiLJ--
Notice that the Content-Type is supposedly application/octet-stream which is what I tried consuming before but got the Cannot consume content type exception. I have no idea what would be causing this. I'm using the Advanced Rest Client extension for Chrome to send my request and it looks something like this: https://i.imgur.com/KvKCIkl.jpg
Any thoughts?
#PUT
#Path("{key}")
#Consumes("application/octet-stream")
public Response addData(
final #PathParam("key") String key,
final InputStream data) {
final Service service = new Service();
try {
service.addData(key, data);
} finally {
IOUtils.closeQuietly(data
}
return Response.status(204).build();
}
A multipart/form-data message contains a series of parts divided by a boundary. Every part has its own Content-Type. So in your example Content-Type: application/octet-stream is the Content-Type of one (and probably the only one) part but the Content-Type of the whole message is multipart/form-data. A full message with multiple parts could look like this:
Content-Type: multipart/form-data; boundary=WebKitFormBoundaryfuQalizBHtg1BiLJ
------WebKitFormBoundaryfuQalizBHtg1BiLJ
Content-Disposition: form-data; name="fileUpload1"; filename="uploadedFile.extension"
Content-Type: application/octet-stream
/* file information here */
------WebKitFormBoundaryfuQalizBHtg1BiLJ--
------WebKitFormBoundaryfuQalizBHtg1BiLJ
Content-Type: text/plain
/* some text here */
------WebKitFormBoundaryfuQalizBHtg1BiLJ--
I am trying to send a zipfile from my android application to our server and I keep getting a 411 length required error.
Here is the code that I am using to do that.
HttpPost post = new HttpPost("http://www.xyz.org/upload.json");
post.setHeader(C.constants.HTTP_CONTENT_TYPE, "application/octet-stream");
try {
FileInputStream fis = new FileInputStream("/data/data/org.myapp.appname/app_content.zip");
InputStreamEntity reqEntity = new InputStreamEntity(fis, -1);
post.setEntity(reqEntity);
String response = doPost(post);
Log.v(tag, "response from server " + response);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
What am I doing wrong here and may I also know how I can add more parameters with this post to send them to the server.
You should use a multipart MIME type, and parts for each parameters and for the files. See this old blog post of mine.
As you should know, an HTTP request (and response, too) is made up of two section: a header and a body (also called entity). In the header you specify a Content-Type so that the server script knows how to interpret the following bytes (you can also specify the encoding for textual data on the same line).
After the header, the client sends an empty line and an optional entity. A multipart entity is like a stack of parts separated by a boundary. This is what your desired HTTP request should look like on the wire:
POST /path/to/script.json HTTP/1.1
Host: localhost
Content-Type: multipart/form-data; boundary=a2ksdf0?--
a2ksdf0?--
Content-Disposition: form-data; name="profile_picture"; filename="me.png"
Content-Type: image/png
<content here>
a2ksdf0?--
Content-Disposition: form-data; name="username";
Content-Type: text/plain
Joe Black
BTW, it's the first time I see an upload script named upload.json. What do you use on the server side?