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--
Related
I have an endpoint setup using Apache Camel to receive a multipart/form-data HTTP request. Essentially I am trying to submit a data file and a configuration file for processing. The request is as follows (generated by Postman):
POST /upload HTTP/1.1
Host: localhost:8900
Content-Length: 363
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
----WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="data"; filename="data-file.json"
Content-Type: application/json
(data)
----WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="config"; filename="config-file.json"
Content-Type: application/json
(data)
----WebKitFormBoundary7MA4YWxkTrZu0gW
My route is set up like so:
#Component
public class FileReceiverRoute extends RouteBuilder {
#Override
public void configure() throws Exception {
rest()
.post("/upload")
.consumes(MediaType.MULTIPART_FORM_DATA_VALUE)
.bindingMode(RestBindingMode.off)
.route().routeId("upload-route")
.unmarshal().mimeMultipart()
.setHeader(Exchange.FILE_NAME, () -> UUID.randomUUID().toString())
.to("file:{{temp.input.files.dir}}")
.process(configFileProcessor)
// on to further processing
}
}
And my config file processor:
#Component
public class ConfigFileProcessor implements Processor {
#Override
public void process(Exchange exchange) throws Exception {
Message message = exchange.getIn();
AttachmentMessage attachmentMessage = exchange.getMessage(AttachmentMessage.class);
Map<String, Attachment> attachmentObjects = attachmentMessage.getAttachmentObjects();
// this fails - the key is instead the file name "config-file.json"
Attachment configAttachment = attachmentObjects.get("config");
}
}
I want to be able to retrieve the key-value pairs from the form-data and process the data and config files accordingly. Instead I get the following behaviour:
The first value in the form (in this case data-file.json) is parsed into the Camel message body, and the key seems to be discarded. The rest of the entries are parsed into an AttachmentMessage. This behaviour is documented here https://stackoverflow.com/a/67566273/11248602
The keys in the AttachmentMessage are not the original keys from the form-data request, but the filenames (e.g. config-file.json)
Is there any way to parse this request into a map or similar structure so that all the original keys and values can be accessed?
For the sake of clarity, as the proposed solution here above seems to work, a bit more explanations (although it is more a workaround than a solution):
Starting from:
Map<String, Attachment> attachmentObjects = attachmentMessage.getAttachmentObjects();
It is possible to browse all map entries, and for each found Attachment object, examine the attachment headers using getHeaderNames(), among other the 'Content-Disposition' one:
Content-Disposition: form-data; name="data"; filename="data-file.json"
which can finally be parsed to grab the form name ('data' in this example).
Not straightforward true, but this apparently works...
I am trying to understand how HTTP protocol works, So I tried to add headers manually to java Socket to send a request to httpbin.org as shown below:
BufferedWriter wr = new BufferedWriter(/*socket Outputstream*/)
wr.write("POST post HTTP/1.1\r\n");
wr.write("Host: httpbin.org\r\n");
wr.write("Accept: */*\r\n");
wr.write("Content-Length: "+data.length()+"\r\n");
wr.write("Content-Type: multipart/form-data; boundary=---WebKitFormBoundary67\r\n");
wr.write("\r\n");
wr.write(data);
wr.flush();
In above code data is the payload of HTTP request that looks exactly as below:
---WebKitFormBoundary67
Content-Disposition: form-data; name="field1"
value1
---WebKitFormBoundary67
Content-Disposition: form-data; name="field2"; filename="example.txt"
Java is better when it run long
---WebKitFormBoundary67--
But the server httpbin.org is not identifying any files attached, am I missing anything?
multipart/form-data is a multipart MIME message as defined in RFC 2046. The basic structure of a multipart MIME message in an example of a multipart/form-data message looks like this:
Content-type: multipart/form-data; boundary=foo
--foo
Content-Disposition: form-data; name=key1
abcde
--foo
Content-Disposition: form-data; name=key2; filename=foo.txt
01234
--foo--
As you can see, the boundary foo is defined in the boundary attribute, is used as delimiter between the parts with --foo and is used as the final boundary as --foo--.
Your code instead defines the boundary not as foo but as --foo and then tries to still use only --foo as a separator between the parts. To correct your code you would either need to set the boundary to only -WebKitFormBoundary67 instead of ---WebKitFormBoundary67, or use -----WebKitFormBoundary67 as separator instead of only ---WebKitFormBoundary67.
I am using Spring 5.0.1 and servlet 3.1.0
When user sends multipart/form-data in the request, spring is able to parse the request and make the parts out of it.
request.getParts() will have those provided multiparts.
But when user sends multipart/report (content-type), spring does not parse this request properly.
It does not give any exception but it does not store anything in the request parts.
request.getParts() will return empty array.
Is there any configuration that has to be done so that spring parses any kind of multipart data.
Posting my code and request payload below:
REST API does not have any restriction on the content type. It takes only request and response as parameters as shown below:
#RequestMapping (value = "/rest/external/integration/{serviceName}", method = RequestMethod.POST)
public void executeAssemblyExternal (HttpServletRequest request,
HttpServletResponse response, #PathVariable String serviceName) throws Exception
{
Parts[] requestParts = request.getParts();
}
Content-type header which is being sent with the request is :
Content-Type multipart/report; Report-Type=disposition-notification; boundary="----=_Part_82_645653877.1526452736757"
Multipart data which is being sent to the REST API is as below:
------=_Part_82_645653877.1526452736757
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
MDN for -
Message ID: <1088014046.24.1526452734879#MCBKUM03.eur.ad.sag>
From: SenderAS2
To: ReceiverAS2
Received on: 2018-05-16 at 12:08:56 (IST)
Status: processed
Comment: This is not a guarantee that the message has been completely processed or understood by the receiving translator
------=_Part_82_645653877.1526452736757
Content-Type: message/disposition-notification
Content-Transfer-Encoding: 7bit
Reporting-UA: webMethods Integration Server
Original-Recipient: rfc822; ReceiverAS2
Final-Recipient: rfc822; ReceiverAS2
Original-Message-ID: <1088014046.24.1526452734879#MCBKUM03.eur.ad.sag>
Received-content-MIC: SezQZhP0aSchqB1zCO0Dq4J0u3U=, sha1
Disposition: automatic-action/MDN-sent-automatically; processed
------=_Part_82_645653877.1526452736757--
As Deinum mentioned in a comment, servlet can not handle multipart requests other than multipart/form-data.
So Written a custom dispatcherServlet where requests having header Content-Type as multipart with subtype other than form-data will be bypassed from getting processed through MultipartResolver.
By doing this request.getInputStream() will have whole multipart data as sent by the user. Necessary actions can be performed on this inputstream at the server side.
I am trying to parse a request body where
Content-type: application/vnd.contentful.management.v1+json
When I give Content-type: application/json
it works fine but Contentful CMS passes the above content-type so I have to parse this somehow.
Seems that you are using the contentful Java SDK right ?
That header is filled by the SDK, is there a reason that you need to parse that header ?
I found the solution.
If the body is of type json it by default look for Content-type application/json in header.
To avoid the validation of the Content-Type header is JSON I used this and it worked.
#BodyParser.Of(BodyParser.TolerantJson.class)
I am using apache http library to build and send a multi-part http request that has a file part in the body. Here is a little sample of my request
Request POST HTTPS://hostname:9443/di/resources/upload?logonId=user1 HTTP/1.1:
Headers: Content-Type: multipart/form-data Set-Cookie: Path=/; HttpOnly TrustToken: -1000%2CCaKOjiTFmje3%2Fw0GGcw5%2BDwgxXHjHdQShQgW1QGiHYk%3D
Body: --ncFZGuKp50zCWWImlBFZjxbanSSoJt
Content-Disposition: form-data; name="File 1"; filename="SampleData_en.csv"
Content-Type: application/octet-stream
Content-Transfer-Encoding: binary
Identifier,title,,,,,,,,,,,,,,
Plan: Entries (1) or ent2 (2) ,2,"Set to 1 to specify plan is for Catalog Entries, set to 2 etc .....
--ncFZGuKp50zCWWImlBFZjxbanSSoJt--
The project is that the service is based on apache wink that has a problem decoding the headers in the body which gives this kind of error
Caused by: java.lang.StringIndexOutOfBoundsException
at java.lang.String.substring(String.java:1240)
at org.apache.wink.common.internal.providers.multipart.MultiPartParser.parseHeaders(MultiPartParser.java:264)
at org.apache.wink.common.internal.providers.multipart.MultiPartParser.nextPart(MultiPartParser.java:109)
at org.apache.wink.common.model.multipart.InMultiPart.hasNext(InMultiPart.java:83)
I believe the fix would be to remove the Content-Transfer-Encoding from the body? or change it to maybe a different encoding, maybe base64.
The only problem is that I dont know how to do this using the apache library and haven't been able to find anything examples. Here is the code I am using apache to create the entity portion of my HttpPost request:
MultipartEntityBuilder reqEntity = MultipartEntityBuilder.create();
File file1 = RequestUtils.getFileBody(filePath);
FileBody fileBodyFile1 = new FileBody(file1, org.apache.http.entity.ContentType.create("application/octet-stream"),
file1 .getName());
reqEntity.addPart("File 1", fileBodyFile1);