You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@cxf.apache.org by dahanhsi <da...@gmail.com> on 2012/10/23 09:21:15 UTC

How to get request body with "application/x-form-urlencoded" content-header set

We develop a REST service implemtented in Apache CXF for our client exposed
like this: 

@PUT 
@Path("/process") 
public void doProcess(@PathParam("para") String para, String reqBody,
@Context MessageContext context); 

The request body is a XML document, and doProcess() will unmarshall the
reqBody String to object itself. 

When the request does not set Content-Type header or set Content-Type header
to "application/xml",  all this works great. I can get reqBody in
doProcess() 

The problem is that the client is not setting the right content-type header
(should be "application/xml" but client sets
"application/x-form-urlencoded"). 

When request content-type header is "application/x-form-urlencoded", I can
not get reqBody in doProcess() (It's null) 

Any ideas? 

Regards, 
Mark 




--
View this message in context: http://cxf.547215.n5.nabble.com/How-to-get-request-body-with-application-x-form-urlencoded-content-header-set-tp5717220.html
Sent from the cxf-user mailing list archive at Nabble.com.

Re: How to get request body with "application/x-form-urlencoded" content-header set

Posted by Sergey Beryozkin <sb...@gmail.com>.
On 25/10/12 13:30, dahanhsi wrote:
> Sergey Beryozkin-5 wrote
>> On 25/10/12 04:50, dahanhsi wrote:
>>> hi Sergey,
>>>
>>> by following your advice, I added the code below in doProcess() and
>>> finally
>>> got the request body:
>>>
>>> HttpServletRequest request = context.getHttpServletRequest();
>>> Enumeration pNames = request.getParameterNames();
>>> while(pNames.hasMoreElements()){
>>>       String name=(String)pNames.nextElement();
>>>       String value=servletRequest.getParameter(name);
>>>       System.out.println(name + "=" + value);
>>> }
>>>
>>>
>>> But in my another restful operation:
>>> @PUT
>>> @Path("/upload")
>>> public void doUpload(... @Context MessageContext context ...){
>>>      ...
>>>      HttpServletRequest request = context.getHttpServletRequest();
>>>      inputStream = servletRequest.getInputStream();
>>>      ...
>>> }
>>>
>>> I also encounter the same problem, and can not write request body from
>>> inputstream.
>>> Client may upload a big file, and exhaust JVM memory if I use above
>>> solution.
>>> How can I fix it?
>>>
>> Calling servletRequest.getInputStream() does not read it into memory, so
>> you can read the stream and save the chunks of the data as needed.
>> Also consider consuming multipart/form-data or similar, CXF will save
>> the data to the temp storage if needed.
>>
>> Sergey
>
> I know that inputStream does not read entire body into memory.
>
> When the request hit my servlet
> ===
> PUT /upload HTTP/1.1
> Host: myhost.com
> Content-Length: length
> Content-Type: application/x-form-urlencoded
> Date: date
>
> {big file in body}
> ===
>
> Because content-type is application/x-form-urlencoded, I can not read
> correct body from request.getInputStream in doUpload(). I also can not read
> it from request.getParameterNames(), because it means that the entire body
> is wrote into memory.
>

This is why I mentioned multipart/form-data - this will prevent the 
servlet container from trying to read the stream into the body (note CXF 
can not control/prevent it) and will also lead to managing the big data 
effectively

Sergey

>
>
>
>
>
> --
> View this message in context: http://cxf.547215.n5.nabble.com/How-to-get-request-body-with-application-x-form-urlencoded-content-header-set-tp5717220p5717403.html
> Sent from the cxf-user mailing list archive at Nabble.com.


-- 
Sergey Beryozkin

Talend Community Coders
http://coders.talend.com/

Blog: http://sberyozkin.blogspot.com

Re: How to get request body with "application/x-form-urlencoded" content-header set

Posted by dahanhsi <da...@gmail.com>.
Sergey Beryozkin-5 wrote
> On 25/10/12 04:50, dahanhsi wrote:
>> hi Sergey,
>>
>> by following your advice, I added the code below in doProcess() and
>> finally
>> got the request body:
>>
>> HttpServletRequest request = context.getHttpServletRequest();
>> Enumeration pNames = request.getParameterNames();
>> while(pNames.hasMoreElements()){
>>      String name=(String)pNames.nextElement();
>>      String value=servletRequest.getParameter(name);
>>      System.out.println(name + "=" + value);
>> }
>>
>>
>> But in my another restful operation:
>> @PUT
>> @Path("/upload")
>> public void doUpload(... @Context MessageContext context ...){
>>     ...
>>     HttpServletRequest request = context.getHttpServletRequest();
>>     inputStream = servletRequest.getInputStream();
>>     ...
>> }
>>
>> I also encounter the same problem, and can not write request body from
>> inputstream.
>> Client may upload a big file, and exhaust JVM memory if I use above
>> solution.
>> How can I fix it?
>>
> Calling servletRequest.getInputStream() does not read it into memory, so 
> you can read the stream and save the chunks of the data as needed.
> Also consider consuming multipart/form-data or similar, CXF will save 
> the data to the temp storage if needed.
> 
> Sergey

I know that inputStream does not read entire body into memory.

When the request hit my servlet
===
PUT /upload HTTP/1.1 
Host: myhost.com 
Content-Length: length 
Content-Type: application/x-form-urlencoded 
Date: date 

{big file in body}
===

Because content-type is application/x-form-urlencoded, I can not read
correct body from request.getInputStream in doUpload(). I also can not read
it from request.getParameterNames(), because it means that the entire body
is wrote into memory.






--
View this message in context: http://cxf.547215.n5.nabble.com/How-to-get-request-body-with-application-x-form-urlencoded-content-header-set-tp5717220p5717403.html
Sent from the cxf-user mailing list archive at Nabble.com.

Re: How to get request body with "application/x-form-urlencoded" content-header set

Posted by Sergey Beryozkin <sb...@gmail.com>.
On 25/10/12 04:50, dahanhsi wrote:
> hi Sergey,
>
> by following your advice, I added the code below in doProcess() and finally
> got the request body:
>
> HttpServletRequest request = context.getHttpServletRequest();
> Enumeration pNames = request.getParameterNames();
> while(pNames.hasMoreElements()){
>      String name=(String)pNames.nextElement();
>      String value=servletRequest.getParameter(name);
>      System.out.println(name + "=" + value);
> }
>
>
> But in my another restful operation:
> @PUT
> @Path("/upload")
> public void doUpload(... @Context MessageContext context ...){
>     ...
>     HttpServletRequest request = context.getHttpServletRequest();
>     inputStream = servletRequest.getInputStream();
>     ...
> }
>
> I also encounter the same problem, and can not write request body from
> inputstream.
> Client may upload a big file, and exhaust JVM memory if I use above
> solution.
> How can I fix it?
>
Calling servletRequest.getInputStream() does not read it into memory, so 
you can read the stream and save the chunks of the data as needed.
Also consider consuming multipart/form-data or similar, CXF will save 
the data to the temp storage if needed.

Sergey

> thank you for your help!
>
>
>
>
>
>
>
> --
> View this message in context: http://cxf.547215.n5.nabble.com/How-to-get-request-body-with-application-x-form-urlencoded-content-header-set-tp5717220p5717375.html
> Sent from the cxf-user mailing list archive at Nabble.com.


-- 
Sergey Beryozkin

Talend Community Coders
http://coders.talend.com/

Blog: http://sberyozkin.blogspot.com

Re: How to get request body with "application/x-form-urlencoded" content-header set

Posted by dahanhsi <da...@gmail.com>.
hi Sergey,

by following your advice, I added the code below in doProcess() and finally
got the request body:

HttpServletRequest request = context.getHttpServletRequest();
Enumeration pNames = request.getParameterNames(); 
while(pNames.hasMoreElements()){
    String name=(String)pNames.nextElement();
    String value=servletRequest.getParameter(name);
    System.out.println(name + "=" + value);
}


But in my another restful operation:
@PUT  
@Path("/upload")  
public void doUpload(... @Context MessageContext context ...){
   ...
   HttpServletRequest request = context.getHttpServletRequest();
   inputStream = servletRequest.getInputStream();
   ...
} 

I also encounter the same problem, and can not write request body from
inputstream.
Client may upload a big file, and exhaust JVM memory if I use above
solution.
How can I fix it?

thank you for your help!
 






--
View this message in context: http://cxf.547215.n5.nabble.com/How-to-get-request-body-with-application-x-form-urlencoded-content-header-set-tp5717220p5717375.html
Sent from the cxf-user mailing list archive at Nabble.com.

Re: How to get request body with "application/x-form-urlencoded" content-header set

Posted by Sergey Beryozkin <sb...@gmail.com>.
On 23/10/12 12:56, dahanhsi wrote:
> Hi,
> thank you for your reply,
>
> My request is HTTP PUT request with a XML document in it's body, just like
> example bellow:
> ===
> PUT /process HTTP/1.1
> Host: myhost.com
> Content-Length: length
> Content-Type: application/x-form-urlencoded (added by client lib)
> Date: date
>
> <myXmlDocument>
> <myElement>myValue</myElement>
> </myXmlDocument>
> ===
>
> so the request has a XML payload, and has no form payload.
>
> My question is,
> When the Content-Type value is "application/xml" or other values except
> "application/x-form-urlencoded",
> I can get the XML String from reqBody in doProcess().
>
> When the Content-Type value is "application/x-form-urlencoded", I can not
> get the XML String, and reqBody is null. Why?
>
> How to get reqBody when Content-Type is "application/x-form-urlencoded"?

Please refer to my previous message. I think you get 'null' because the 
message body is consumed in this case at the servlet level, therefore I 
recommend you to introduce a dedicated method for getting the form 
payloads properly - to be honest I'm not sure that will work either 
given that it is XML after all, not a proper form payload.

So, as the first step, lets explore why you get "null". The method 
expects String so as I said, all the String provider does is reads the 
input stream, no matter what content-type is there, you get null, 
therefore the body is empty already. Now, you can inject 
HttpServletRequest (as @Context) and if 'String' method parameter
is null then check

request.getParameterNames()

Perhaps you should return 400 or 415 for this case

Sergey
>
> thanks!
>
>
>
>
>
>
> --
> View this message in context: http://cxf.547215.n5.nabble.com/How-to-get-request-body-with-application-x-form-urlencoded-content-header-set-tp5717220p5717243.html
> Sent from the cxf-user mailing list archive at Nabble.com.


Re: How to get request body with "application/x-form-urlencoded" content-header set

Posted by dahanhsi <da...@gmail.com>.
Hi, 
thank you for your reply,

My request is HTTP PUT request with a XML document in it's body, just like
example bellow: 
===
PUT /process HTTP/1.1
Host: myhost.com
Content-Length: length
Content-Type: application/x-form-urlencoded (added by client lib)
Date: date

<myXmlDocument>
<myElement>myValue</myElement>
</myXmlDocument>
===

so the request has a XML payload, and has no form payload.

My question is, 
When the Content-Type value is "application/xml" or other values except
"application/x-form-urlencoded",
I can get the XML String from reqBody in doProcess().

When the Content-Type value is "application/x-form-urlencoded", I can not
get the XML String, and reqBody is null. Why?

How to get reqBody when Content-Type is "application/x-form-urlencoded"?

thanks!






--
View this message in context: http://cxf.547215.n5.nabble.com/How-to-get-request-body-with-application-x-form-urlencoded-content-header-set-tp5717220p5717243.html
Sent from the cxf-user mailing list archive at Nabble.com.

Re: How to get request body with "application/x-form-urlencoded" content-header set

Posted by Sergey Beryozkin <sb...@gmail.com>.
Hi
On 23/10/12 08:21, dahanhsi wrote:
> We develop a REST service implemtented in Apache CXF for our client exposed
> like this:
>
> @PUT
> @Path("/process")
> public void doProcess(@PathParam("para") String para, String reqBody,
> @Context MessageContext context);
>
> The request body is a XML document, and doProcess() will unmarshall the
> reqBody String to object itself.
>
> When the request does not set Content-Type header or set Content-Type header
> to "application/xml",  all this works great. I can get reqBody in
> doProcess()
>
> The problem is that the client is not setting the right content-type header
> (should be "application/xml" but client sets
> "application/x-form-urlencoded").
>
> When request content-type header is "application/x-form-urlencoded", I can
> not get reqBody in doProcess() (It's null)
>
> Any ideas?
>

I can only think of the form parameters being 'pushed' into 
HttpServletRequest parameters/attributes which can happen sometimes at 
the servlet level, say, by spring security filters. When a form provider 
is used (ex, when @FormParam or MultivaluedMap parameter is available in 
the signature), it checks servlet request object if the input stream is 
empty. But when you have 'String' - a single attempt by a String 
provider to read the input stream is all what is done.

Try adding a method dedicated to consuming form payloads

Cheers, Sergey

> Regards,
> Mark
>
>
>
>
> --
> View this message in context: http://cxf.547215.n5.nabble.com/How-to-get-request-body-with-application-x-form-urlencoded-content-header-set-tp5717220.html
> Sent from the cxf-user mailing list archive at Nabble.com.


-- 
Sergey Beryozkin

Talend Community Coders
http://coders.talend.com/

Blog: http://sberyozkin.blogspot.com