apache cxf MultiPart request has no Content-Length header - java

I'm having below code to send a multipart/form-data request.
List<Attachment> multipartData = new ArrayList<>();
ContentDisposition cd1 = new ContentDisposition("form-data; name=\"file\";
filename="+fileObj.getName());
FileInputStream inputStream = new FileInputStream(fileObj);
multipartData.add(new Attachment("file",inputStream, cd1));
MultipartBody multipart = new MultipartBody(multipartData);
In my RestClient class, I'm using the below lines of code to send a POST request using JAX-RS Client object
if ("POST".equals(method)) {
response = this.client.getBuilder().post(Entity.entity(entity,MediaType.MULTIPART_FORM_DATA));
I checked the HTTP request body using Wiremock and is as below:
Transfer-Encoding: [chunked]
Accept: [*/*]
Cache-Control: [no-cache]
User-Agent: [Apache-CXF/3.2.5]
Connection: [keep-alive]
Host: [127.0.0.1:9990]
Pragma: [no-cache]
Content-Type: [multipart/form-data; boundary="uuid:04b491f5-50de-4f4f-b7c0-cd745136d3d1"]
--uuid:04b491f5-50de-4f4f-b7c0-cd745136d3d1
Content-Type: application/octet-stream
Content-Transfer-Encoding: binary
Content-ID: <file>
Content-Disposition: form-data; name="file"; filename=sample.txt
<File content goes here>
I want to know how the content-length header is missing in the request payload. Is there any way to set the content-length header to the request?
Please help me.

I used the apache cxf WebClient to unset the transfer encoding as chunked.
if ("POST".equals(method)) {
Invocation.Builder builder = this.client.getBuilder();
WebClient.getConfig(builder).getHttpConduit().getClient().setAllowChunking(false);
response = builder.post(Entity.entity(entity,MediaType.MULTIPART_FORM_DATA));
}
With this, the client is able to send the request with content-length header.

Related

XML RPC Header Modification with JAVA

I need to add the authentication while sending xml-rpc request.
POST /Air HTTP/1.1
Content-Length: 1704
Content-Type: text/xml
User-Agent: UGw Server/5.0/1.0
Host: localhost
Authorization: Basic ZmRzdXNlcjpmZHN1c2Vy
But not able to find how to do it.
This is how I am sending the request in JAVA
XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl();
config.setServerURL(new URL("http://localhost:8088/RPC2"));
config.setUserAgent("UGw Server/5.0/1.0");
XmlRpcClient client = new XmlRpcClient();
client.setConfig(config);
Integer result = (Integer)client.execute("translate.sum", params);

Parsing Multipart/mixed in Spring

I want to parse requests like the following in my RestController
POST http://#.#.#.#:#/report HTTP/1.1
User-Agent: Android
Accept: text/html,application/xml,application/json,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
Content-Type: multipart/mixed; boundary=%&REPORT_DIVIDER&%
Authorization: Basic ***
Content-Length: 23236
Host: #.#.#.#:#
Connection: Keep-Alive
Accept-Encoding: gzip
--%&REPORT_DIVIDER&%
Content-Type: application/json
{"content-excluded":true}
--%&REPORT_DIVIDER&%
Content-Disposition: attachment; filename="INSTALLATION"
Content-Type: application/octet-stream
609903cf-fcc0-460c-87db-958e031ac156
--%&REPORT_DIVIDER&%--
This message is conform to rfc1341, yet I cannot find a way to parse this in Spring.
Note that the number of files may vary.
I've already tried using CommonsMultipartResolver or StandardServletMultipartResolver, but both only support multipart/form-data (rfc1867).
Is there any way to parse these request in Spring besides writing my own parser?
While it is not a very nice solution, it was the only one I found:
I essentially reimplemented ServletFileUpload with this class and then loaded it into the apache library with this simple subclass of CommonsMultipartResolver
#Path("api")
#PUT
#Consumes("multipart/mixed")
#Produces("multipart/mixed")
public MultiPart twelve( MultiPart multiPart) throws IOException {
List<BodyPart> bodyParts = multiPart.getBodyParts();
BodyPartEntity bpe = (BodyPartEntity) bodyParts.get(1).getEntity();
}
This is for jersey based spring boot project.

Jersey throws ParseException when uploading file in multipart/form-data request

I am trying to send an mp3 file along with some metadata to my Jersey REST service. For this I am trying to use multipart/form-data content type, however I always get java.text.ParseException: Next event is not a Separator when I send the request. The whole response:
{"restResponse":{
"responseCode":"INVALID_PARAMETER",
"i18nMessage":"Invalid Parameter: Next event is not a Separator",
"responseDescription":"The request contains an invalid parameter"}}
If I remove the mp3 file from the request, it is working properly so I assume there is a problem with how my request is constructed. I am using Paw, which generates request like this:
POST /rest/myapi/recording/multipart HTTP/1.1
Accept: application/json
Accept-Language: en-US
Content-Type: multipart/form-data; boundary=EI6FArOacJKf5JCY5BAA2sbl2IAfN8ty
Cookie: JSESSIONID=a5f5cfa7329142158766a6182645; JSESSIONIDSSO=BAFA3371F6D14A179B0BA6216DD6C119
Host: localhost:8181
Connection: close
User-Agent: Paw/2.2.2 (Macintosh; OS X/10.10.5) GCDHTTPRequest
Content-Length: 44504
--EI6FArOacJKf5JCY5BAA2sbl2IAfN8ty
Content-Disposition: form-data; name="queue"
qMultipart
--EI6FArOacJKf5JCY5BAA2sbl2IAfN8ty
Content-Disposition: form-data; name="datetime"
20151029-021807
--EI6FArOacJKf5JCY5BAA2sbl2IAfN8ty
Content-Disposition: form-data; name="recording"; filename="test4_multiform.mp3"
Content-Type: audio/mpeg
ID3ETT2test4_multiformCOMengiTunPGAP0TENiTunes 12.3.0.44COMhengiTunNORM 00000152 00000152 000013BE 000013BE 0000023E 0000023E 00003F10 00003F10 000002A7 000002A7COMengiTunSMPB 00000000 00000210 00000A30 0000000000015BC0 00000000 0
--- the rest of the recording ---
The serverside handler:
#Path(value = "multipart")
#POST
#Consumes(MediaType.MULTIPART_FORM_DATA)
#Produces(MediaType.APPLICATION_JSON)
public Response receiveFileAndMetadataAsMultipart(
#FormDataParam(RECORDING) InputStream recordingIinputStream,
#FormDataParam(RECORDING) FormDataContentDisposition callRecordingDispositionHeader,
#FormDataParam(QUEUE) String queue,
#FormDataParam(DATETIME) String datetime) throws JSONException, ParseException, IOException {
//do stuff with my recording and metadata
//...
JSONObject response = new JSONObject();
return Response.status(Response.Status.OK).entity(response).build();
}
When I try to send just the file and the content type is not multipart/form-data but application/octet-stream, then it works fine. (I mean not with this handler but one which accepts octet-stream) although the request is very similar. I'll post the request and code for octet stream as well, maybe it helps:
PUT /rest/myapi/recording HTTP/1.1
Accept: application/json
Accept-Language: en-US
Content-Type: application/octet-stream
Cookie: JSESSIONID=a5f5cfa7329142158766a6182645; JSESSIONIDSSO=BAFA3371F6D14A179B0BA6216DD6C119
Host: localhost:8181
Connection: close
User-Agent: Paw/2.2.2 (Macintosh; OS X/10.10.5) GCDHTTPRequest
Content-Length: 55414
ID3BTT2test3_2callsCOMengiTunPGAP0TENiTunes 12.3.0.44COMhengiTunNORM 0000038A 0000038A 00001B3D 00001B3D
--- the rest of the recording ---
Method:
#Path(value = "recording")
#PUT
#Consumes(MediaType.APPLICATION_OCTET_STREAM)
#Produces(MediaType.APPLICATION_JSON)
public Response receiveRecording(InputStream callRecordingInputStream) throws IOException, JSONException {
//do stuff with my recording
//...
JSONObject response = new JSONObject();
return Response.status(Response.Status.OK).entity(response).build();
}
Does anyone have any idea what is wrong? I found this approach with multipart on several places online so I guess it should work doing it like that.
Btw, I also tried removing all of the metadata and just send the recording but the problem was the same.
I have found the issue thanks to #peeskillet's comment, so just in case this exact same thing happens to someone else:
I had a bad import for FormDataContentDisposition.
Wrong:
import com.sun.jersey.core.header.FormDataContentDisposition;
Correct:
import org.glassfish.jersey.media.multipart.FormDataContentDisposition;

Resteasy always get application/json content type on request

I have a web application that use Angularjs on frontend och Resteasy + Jackson on the back end. I'm sending a file from Angular component to a REST method, receiving method looks like this :
#POST
#Path("/upload/attachment/for/{eventId}")
#Consumes(MediaType.MULTIPART_FORM_DATA)
public Response uploadFile(MultipartFormDataInput input,
final #PathParam("eventId") Long eventId,
#Context HttpServletRequest request) {
Map<String, List<InputPart>> uploadForm = input.getFormDataMap();
...my awesome stuff...
return Response.ok().build();
}
And request has following headers when sent :
Accept application/json, text/plain, */*
Accept-Encoding gzip, deflate
Accept-Language en-US,en;q=0.5
Content-Length 347085
Content-Type multipart/form-data; boundary=---------------------------12164806981346771846716776342
Cookie JSESSIONID=aoBd1hgzR3GM8bSG5P-9g-vQ; csrftoken=ziQ7kN7TlMehR2aURDrmaMLYAroMsSpu
Host localhost:9000
Referer http://localhost:9000/local/myapp/index.html
User-Agent Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:32.0) Gecko/20100101 Firefox/32.0
The problem is that THIS request ALWAYS has application/json as a Content-Type instead for multipart/form-data as it says in the headers. And I get :
20:12:00,490 WARN [org.jboss.resteasy.core.SynchronousDispatcher] (http-/127.0.0.1:8080-2) Failed executing POST /events/upload/attachment/for/null: org.jboss.resteasy.spi.UnsupportedMediaTypeException: Cannot consume content type
Already in HttpServletDispatcher the content is wrong.
I can't get if this is JBOSS that set Content-Type to wrong value or some thing else.
Ok, it was that I have an extra layer between angular and server which runs on Node.js and it just tunel requests to the server. I had to add following :
var r = null;
r = request.put({uri: url, json: inReq.body, headers: inReq.headers, form: inReq.form});
inReq.pipe(r).pipe(inRes);
This set all the headers from outgoing request and tunnel the request
Now I have right content-type

Jersey Client set content-type header as text/plain

Using jersey client sending HTTP request. Content-Type header is automatically set as "application/json" (as a nature), but i want to changing "content-type" header with "text/plain" regardless of any specification, standards etc. Jersey version is 2.4.1.
Code
String target = "http://192.168.1.2:10000";
String path = "test3";
Client c = ClientBuilder.newClient ();
WebTarget target = c.target (target).path (path);
Entity<SubscriberBean> json = Entity.json (subscriber);
Builder request = target.request ();
String response = request.post(json, String.class);
Request
POST /test3 HTTP/1.1
Accept: text/html
Content-Type: application/json
User-Agent: Jersey/2.4.1 (HttpUrlConnection 1.6.0_17)
Host: 192.168.1.2:10000
Connection: keep-alive
Content-Length: 278
///**** Some json data ***///
instead of
request.post(json, String.class);
try to use
request.type(MediaType.TEXT_PLAIN).post(json, String.class);
Use Entity.text(entityData) or Entity.entity(entityData, mediaType) methods instead of Entity.json() in your example.

Categories