Spring boot with Apache CXF Multipart request always fails with 400 - spring-boot

I am using spring boot along with Apache CXF. My REST API definition looks as below
 
#PUT
#Consumes(value = {MediaType.MULTIPART_FORM_DATA})
#ApiOperation(value = "Sends a notification")
public boolean sendNotification(
#FormParam(QueryParams.SUBJECT) String subject,
#FormParam(QueryParams.MESSAGE) String message) {
}
When we hit via REST client, we are always getting 400.
PUT /rest/notifications HTTP/1.1
Host: localhost:9080
User-Agent: insomnia/2020.3.3
Content-Type: multipart/form-data; boundary=X-INSOMNIA-BOUNDARY
Accept: /
Content-Length: 231
--X-INSOMNIA-BOUNDARY
Content-Disposition: form-data; name="subject"
A new topic has been created
--X-INSOMNIA-BOUNDARY
Content-Disposition: form-data; name="message"
A new topic has been created
--X-INSOMNIA-BOUNDARY--
We are completely uploaded and fine
Mark bundle as not supporting multiuse
HTTP/1.1 400
Content-Encoding: UTF-8
Date: Tue, 04 Aug 2020 05:08:42 GMT
Content-Type: text/plain
Content-Length: 50
Connection: close

Related

Google Drive API batch request with HTTP

these 2 docs confirm that (1) Google drive API can accept batch request, (2) currently Go-client does not have batch-request feature.
https://developers.google.com/drive/api/v3/batch#java
https://developers.googleblog.com/2018/03/discontinuing-support-for-json-rpc-and.html
I am looking at the example (https://developers.google.com/drive/api/v3/performance#example). I wonder if I can make a batch request with POSTMAN. How to do it? In this example (https://developers.google.com/drive/api/v3/performance#example), is everything below the first "--END_OF_PART" in the HTTP header? How to construct such a batch request in Postman or HTTP in general? Thanks a lot!
The example posted below as well.
POST https://www.googleapis.com/batch/drive/v3
Accept-Encoding: gzip
User-Agent: Google-HTTP-Java-Client/1.20.0 (gzip)
Content-Type: multipart/mixed; boundary=END_OF_PART
Content-Length: 963
--END_OF_PART
Content-Length: 337
Content-Type: application/http
content-id: 1
content-transfer-encoding: binary
POST https://www.googleapis.com/drive/v3/files/fileId/permissions?fields=id
Authorization: Bearer authorization_token
Content-Length: 70
Content-Type: application/json; charset=UTF-8
{
"emailAddress":"example#appsrocks.com",
"role":"writer",
"type":"user"
}
--END_OF_PART
Content-Length: 353
Content-Type: application/http
content-id: 2
content-transfer-encoding: binary
POST https://www.googleapis.com/drive/v3/files/fileId/permissions?fields=id&sendNotificationEmail=false
Authorization: Bearer authorization_token
Content-Length: 58
Content-Type: application/json; charset=UTF-8
{
"domain":"appsrocks.com",
"role":"reader",
"type":"domain"
}
--END_OF_PART--

Applozic Platform Chat API - Uploading message attachments

I'm integrating with applozic for a client, and I need to send messages with attachments to users. I'm following the steps here: https://docs.applozic.com/docs/1-1-user-chat-and-group-chat-api#section-send-message-with-attachment on how to do this.
I'm having trouble with step 2:
Step 2. Call Url With multipart :
Call API with your file object attached to files[] array:
the requests I send are rejected with a 405 error, for example....
Request:
POST /_ah/upload/AMmfu6ZQrGP3Szfk1GuQAb_2a3J7PPWhQoiRbTnEjLp2MIzpuoeHrYryXhlzI6NW9JikjpJbT-HEtHAIk3og-Gl5EesCzBASipgtq1Hvh-PN90sjvasjRBvtO5XIFWi08gGfqTYUNT0C/ALBNUaYAAAAAWocIx4JPtA2a7LU00w1_pRui2Q3NjLR5/
application-key: XXXX
authorization: Basic XXXXX
cache-control: no-cache
accept: */*
host: applozic.appspot.com
accept-encoding: gzip, deflate
content-type: multipart/form-data; boundary=--------------------------523557777486909202804628
content-length: 286288
--------------------------523557777486909202804628
Content-Disposition: form-data; name="file"; filename="attachment.pptx"
Content-Type: application/vnd.openxmlformats-officedocument.presentationml.presentation
....file data....
Response:
HTTP/1.1 405
status: 405
x-guploader-uploadid: AEnB2UpLhLC9VKz0ysfP-WcNTgGCFc_67dVEp_-ANZsLTvWfEOFgyMWKKvpehGa3I6E9Q_s8S7LQAcYFlTt-J8LwVqRosha6lNros6eECUP5JdJ_RsZMW9g
access-control-allow-origin: *
access-control-allow-methods: POST, GET, OPTIONS, DELETE
access-control-max-age: 3600
access-control-allow-headers: UserId-Enabled, Authorization, Application-Key, Source, Content-Type
allow: GET
x-cloud-trace-context: 728352eed99001ff946db65f68daf518;o=1
x-appengine-estimated-cpm-us-dollars: $0.000026
x-appengine-resource-usage: ms=93 cpu_ms=605
date: Fri, 16 Feb 2018 16:29:37 GMT
pragma: no-cache
expires: Fri, 01 Jan 1990 00:00:00 GMT
cache-control: no-cache, must-revalidate
content-length: 0
server: UploadServer
content-type: text/html; charset=UTF-8
alt-svc: hq=":443"; ma=2592000; quic=51303431; quic=51303339; quic=51303338; quic=51303337; quic=51303335,quic=":443"; ma=2592000; v="41,39,38,37,35"
Could someone tell me what i'm missing here? It's responding with allow: GET which doesn't make sense, am I failing auth somehow?
Is there any more documentation available on this feature?
Step 1. Get Url to Upload File
Call API:
https://applozic.appspot.com/rest/ws/aws/file/url?data=1478763491992
where data= currentTime in long
API Response String:
https://applozic.appspot.com/_ah/upload/AMmfu6YAZpXFUYvC7wqIcW7msh8-YF1d7Tsh1UOTSCzpx2vinrcLQRtVfWbFHHXLFunUqsSLe1dYsDbsJxIO28cNcGrECf7LfFaNSycct-Sybd9KAZWk0yk7HybzxbBp4YQEDmMLi4Uf/ALBNUaYAAAAAWovz3TcYX24yam5K3embIkgQ6Q1pGIRf/
Step 2. Call Url With multipart :
Call API with your file object attached to files[] array(Parameter:files[]):
https://applozic.appspot.com/_ah/upload/AMmfu6YAZpXFUYvC7wqIcW7msh8-YF1d7Tsh1UOTSCzpx2vinrcLQRtVfWbFHHXLFunUqsSLe1dYsDbsJxIO28cNcGrECf7LfFaNSycct-Sybd9KAZWk0yk7HybzxbBp4YQEDmMLi4Uf/ALBNUaYAAAAAWovz3TcYX24yam5K3embIkgQ6Q1pGIRf/
filetMeta json Response:
{"fileMeta":{"blobKey":"AMIfv96n1wlMLpa3R_1i4nbFc4L1RLG81W5RovnPqMhVspzzJv5WBbnYgI4uwZkNjvzszNqsWwEQU6mrYoYsaoa2Vhi45p3P7bvQhAO1ciEL1K1yZJ2HB-goYPULYumC7LA8h33p_Ry
JBewFK8FogMDPR4_4zjClIg","contentType":"image/png","createdAtTime":"1478763491698","name":"applozic.png","size":"8694","thumbnailUrl":"https://lh3.googleusercontent
.com/EfnmKkzLtwBgYQq9UWc26oVqSZUiGukhXQgq7ns9a3G53ZAveFOszamvsqD-tbOfuirqERBO0QR60xFgYiGr=s120"}}
Try this request :
Post request
Url:-
https://applozic.appspot.com/_ah/upload/AMmfu6ZB1z1BBDQMh_ztllvkde5mest9aFeqDHoSmCLzGH3vEtqQLKKOZG820ONgNCOc3BatKJL-59Tppm76zvyfw773R4lEa7m3gaM4cdKGbDU5oy8R_9zt_PT12j8xYSK2oh3rO3xa/ALBNUaYAAAAAWoq31zwU986GLyomPgxjoJb6qHuf4iIx/
Param:files[]

How to uplaod a file to a multipart post request in ruby

I am trying to upload a file(huge) to a multipart post request in ruby. I use the following code but it gives me 500 internal server error:
RestClient.post("urladdress',
:name_of_file_param => File.new('path_of_the_file_to_be_uploaded'))
Following is the multipart request from the endpoint I am using currently:
POST address HTTP/1.1
Host: ip address
Content-Length: 325
Cache-Control: max-age=0
Origin: http://address
Upgrade-Insecure-Requests: 1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryol2BpbpZ9cZlqFyb
User-Agent: blah blah blah
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Referer: http://address
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
------WebKitFormBoundaryol2BpbpZ9cZlqFyb
Content-Disposition: form-data; name="uploadedFile"; filename="blah.csv"
Content-Type: text/csv
123456789010290
123456789010290
------WebKitFormBoundaryol2BpbpZ9cZlqFyb
Content-Disposition: form-data; name="submit"
Upload APK
------WebKitFormBoundaryol2BpbpZ9cZlqFyb--
Also if someone can help me with creating a new endpoint which can be used to upload the file without using multipart that is fine too.
Thanks,
RV

How to handle multipart/form-data with different content-types?

How to parse multipart/form-data using Spring framework which has different content-types?
Content-Type: multipart/form-data; boundary=----------287032381131322
Content-Length: 999
----------287032381131322
Content-Disposition: form-data; name="targetDevices"
Content-Type: text/JSON
[ “12345678”, “22345678”, “32345678 ]
----------287032381131322
Content-Type:application/octet-stream
Content-Length:<file length>
<file goes here…>

Using CommonsMultipartResolver to parse an HTTP request with embedded multipart content

I am using Spring Integration to receive an HTTP request which has multipart content nested inside a multipart request as shown below. When using CommonsMultipartResolver as the resolver the LinkedMultiValueMap passed to the receiving service activator contains a map of all the parts but the imbedded multipart is an UploadedMultipartFile which contains the entire content. In the sample boundary2----extKDvsqGExTQI2WVuplHFCUQJ3XVL is the boundary of the embedded multipart.
How can I get the embedded multipart parsed into a LinkedMultiValueMap so that I can get the version and payload? Is it possible for the CommonsMultipartResolver to do this or is there another way to parse it?
Http Request:
POST http://xxxxx:8087/edi846Inbound HTTP/1.1
Content-Type: multipart/form-data;boundary=DM1-Sb0636VXPQNO3412Ygegb9suqr
.......
Content-Length: 2787
--DM1-Sb0636VXPQNO3412Ygegb9suqr
Content-Disposition: form-data; name="from"
Content-Type: text/plain;charset=ISO-8859-1 Content-Length: 7
gisb-acknowledgement-receipt
--DM1-Sb0636VXPQNO3412Ygegb9suqr
Content-Disposition: form-data; name="input-format" Content-Type:
text/plain;charset=ISO-8859-1 Content-Length: 3
X12
--DM1-Sb0636VXPQNO3412Ygegb9suqr
Content-Disposition: form-data; name="input-data"; filename="TEST-DTEBS_846_3563_10142015102600.x12"
Content-Type:
multipart/encrypted;boundary=boundary2--extKDvsqGExTQI2WVuplHFCUQJ3XVL protocol:
application/pgp-encrypted
boundary2----extKDvsqGExTQI2WVuplHFCUQJ3XVL
Content-Disposition: form-data; name="version" Content-Type:
application/pgp-encrypted Content-Length: 10
Version: 1
boundary2----extKDvsqGExTQI2WVuplHFCUQJ3XVL
Content-Disposition: form-data; name="payload" Content-Type: application/octet-stream Content-Length:
1118
-----BEGIN PGP MESSAGE----- Version: BCPG v1.47
hQIOA8aa0/bci2e/EAf/fkgOBK+cOoeY+44htcvjE9Sxk9RK73aOEaxDOBNqFOsV
Nzw1va7cc7wzYOTlHhZV/MkpXq+IrZV316moJu1EAhscN9YmyReVDOzrkzZ1hBmq
V2MlAr5/CRqS7nQEmCqy/Mz0STtAPZNg3FOh8F79dJnRws5/SdW+zvn2MoSvGTs3
0YvjmtPq2YyVkMlAvJ62f903UYNIiAcEe1k8gWDVW9LJ4tGud+8H0bsG8EFWPsSI
b5rON+MKGykbWGnbSrOy9cqslJaghj91r7ZbsXXXiRn9v4rpOardfiBEnoamI5Tz
jfDKESnr7CqoZgb62je+NJrB5puoAwy8LTynXx4cmQgAnf8lb6f+mIxa1U1Mu6iR
KNTjrH83Cx2BjTra8E8hu0O7GvuczGfA9NiONmxbglgKK58/QVYdlsZUiGTaWkkY
4nMHiaFe9TiPQ6W2vMGutLFR3V6YSshchCskl6cP1OdaIXCYgzZKIjUWHePzd/ds
zCZeNqul1N7iIQ0L5lfSGgfB2eDeeK3JKFjetrrbJQXz0+XeTZLPMSMr6W5Ggq3l
PnoJVTrxUd3b2WKgR4FZB+imYRWEz5KLnB5ZVedC+fU24bECcNptrTQaZZUWnR3Z
ABJqz8avBrNV0Jf9BaFRxcWkrWyr4KtxDArxXOuMHNvGVtj+hhPZcPGj3N9Xam3E
6snAGebIiAEivZPYLVVVk0lZW2H0ISwkKkjD8qs7h8wa7Qbchp2K5IyENEzi20oe
FNRoCwHyjsCY0nECHCG3WON0EXG2DZDTvA17OoyfuKnRT09FVt3OOEPTV048vUid
kUoGa7uT7ud9En7uNSfmDpw+xHxB38N986BKBtoeJlGgDYISJkIgr40TIKMLE/Yc
whDnmKxT68dfSGcv/DIUzYs+d/OBzSpHIWK87me5QnhmLTQ1xwfwtFoTyk6B3Vzx
ljlZFD6e7PJfjo/RIhb0zMvtBvRTONRrMXKRdRY=
=serM
-----END PGP MESSAGE-----
boundary2----extKDvsqGExTQI2WVuplHFCUQJ3XVL--
--DM1-Sb0636VXPQNO3412Ygegb9suqr--
Embedded content from Map:
boundary2----extKDvsqGExTQI2WVuplHFCUQJ3XVL
Content-Disposition: form-data; name="version" Content-Type: application/pgp-encrypted Content-Length:
10
Version: 1
boundary2----extKDvsqGExTQI2WVuplHFCUQJ3XVL
Content-Disposition: form-data; name="payload" Content-Type: application/octet-stream Content-Length:
1118
-----BEGIN PGP MESSAGE----- Version: BCPG v1.47
hQIOA8aa0/bci2e/EAf/fkgOBK+cOoeY+44htcvjE9Sxk9RK73aOEaxDOBNqFOsV
Nzw1va7cc7wzYOTlHhZV/MkpXq+IrZV316moJu1EAhscN9YmyReVDOzrkzZ1hBmq
V2MlAr5/CRqS7nQEmCqy/Mz0STtAPZNg3FOh8F79dJnRws5/SdW+zvn2MoSvGTs3
0YvjmtPq2YyVkMlAvJ62f903UYNIiAcEe1k8gWDVW9LJ4tGud+8H0bsG8EFWPsSI
b5rON+MKGykbWGnbSrOy9cqslJaghj91r7ZbsXXXiRn9v4rpOardfiBEnoamI5Tz
jfDKESnr7CqoZgb62je+NJrB5puoAwy8LTynXx4cmQgAnf8lb6f+mIxa1U1Mu6iR
KNTjrH83Cx2BjTra8E8hu0O7GvuczGfA9NiONmxbglgKK58/QVYdlsZUiGTaWkkY
4nMHiaFe9TiPQ6W2vMGutLFR3V6YSshchCskl6cP1OdaIXCYgzZKIjUWHePzd/ds
zCZeNqul1N7iIQ0L5lfSGgfB2eDeeK3JKFjetrrbJQXz0+XeTZLPMSMr6W5Ggq3l
PnoJVTrxUd3b2WKgR4FZB+imYRWEz5KLnB5ZVedC+fU24bECcNptrTQaZZUWnR3Z
ABJqz8avBrNV0Jf9BaFRxcWkrWyr4KtxDArxXOuMHNvGVtj+hhPZcPGj3N9Xam3E
6snAGebIiAEivZPYLVVVk0lZW2H0ISwkKkjD8qs7h8wa7Qbchp2K5IyENEzi20oe
FNRoCwHyjsCY0nECHCG3WON0EXG2DZDTvA17OoyfuKnRT09FVt3OOEPTV048vUid
kUoGa7uT7ud9En7uNSfmDpw+xHxB38N986BKBtoeJlGgDYISJkIgr40TIKMLE/Yc
whDnmKxT68dfSGcv/DIUzYs+d/OBzSpHIWK87me5QnhmLTQ1xwfwtFoTyk6B3Vzx
ljlZFD6e7PJfjo/RIhb0zMvtBvRTONRrMXKRdRY=
=serM
-----END PGP MESSAGE-----
boundary2----extKDvsqGExTQI2WVuplHFCUQJ3XVL--
Not sure what you mean, but I'd suggest to DEBUG the code in the MultipartAwareFormHttpMessageConverter.readMultipart(). That is a place where an UploadedMultipartFile appears.
A quick look at the CommonsMultipartResolver seems to indicate it doesn't support nested multiparts.
It might not be too hard to subclass it and override parseRequest(), but you might have to dig into commons-fileupload as well.
EDIT
Regarding multipart response:
I just patched the http sample and found that, as long as the request has a proper accept header, simply returning a MultiValueMap "just works".
If you need more control over the part headers, you would need to subclass the AllEncompassingFormHttpMessageConverter and override getHttpEntity() to insert extra headers and configure the gateway to use the custom adapter. Basic headers work ok, though - this...
MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
map.add("foo", "Hello");
map.add("bar", "baz");
map.add("fiz", "qux".getBytes());
return map;
...results in this...
--6_zk8PXoaiUO_By2XJuUpjs5CEEnYM-wj0qE
Content-Disposition: form-data; name="foo"
Content-Type: text/plain;charset=ISO-8859-1
Content-Length: 5
Hello
--6_zk8PXoaiUO_By2XJuUpjs5CEEnYM-wj0qE
Content-Disposition: form-data; name="bar"
Content-Type: text/plain;charset=ISO-8859-1
Content-Length: 3
baz
--6_zk8PXoaiUO_By2XJuUpjs5CEEnYM-wj0qE
Content-Disposition: form-data; name="fiz"
Content-Type: application/octet-stream
Content-Length: 3
qux
--6_zk8PXoaiUO_By2XJuUpjs5CEEnYM-wj0qE--

Resources