3

I've written a CF10 RESTful web service that accepts a POST from a third party. The POST comes in with successfully with proper headers showing that it's content-type is application/json and content-encoding is gzip.

The body however comes in like this

??VJ.-.??M-?LQ?R22?0W?Q??Os-????b??????_?ZT??175 ????T?E???r??KKJ??3??S]A?@u??%??`?f??FJ???`?

The issue is that in the receiving function the cfargument for body is set to type="string" when really what it should be is type="binary". Unfortunately setting the type to binary causes the call to fail. The calling server receives the following:

Notification response HTTP/1.1 500 Internal Server Error Content-Length: 41 Content-Type: text/plain Server: Microsoft-IIS/7.5 CF_TOMCAT_REUSE_THIS_CONNECTION: FALSE X-Powered-By: ASP.NET Date: Thu, 30 May 2013 19:53:17 GMT Connection: close

{"Message":"Variable BODY is undefined."}

I have no control of the third party call to my REST endpoint.

Does anyone have any ideas that would allow my REST endpoint to receive this gzipped (binary) body? Alternatively, does anyone know how to convert the string representation back into a gzip'd binary that can then be inflated and I can then recover the json packet?

My code looks like this:

<cffunction name="trigger" access="remote" returntype="string" httpmethod="POST">
    <cfargument name="body" type="any" >
    <cfargument name="Length" type="String" restArgsource="Header" restargname="Content-Length" >
    <cfargument name="Type" type="String" restArgsource="Header" restargname="Content-Type">
    <cfargument name="Encoding" type="String" restArgsource="Header" restargname="Content-Encoding" >
    <cfset var result = "HTTP/1.1 200 OK" >
    <!---        Do some processing here     --->
    <cfreturn result>
</cffunction>

Thank you all in advance.

Leigh
  • 28,765
  • 10
  • 55
  • 103
scoDubblT
  • 391
  • 1
  • 2
  • 10
  • Shouldn't your web server (IIS) or Tomcat be handling the compression before it gets to ColdFusion? – Miguel-F May 31 '13 at 14:02
  • --> https://bugbase.adobe.com/ – Henry May 31 '13 at 21:20
  • What happens if you use "any" for the type? What happens if you pass the value to the toBinary() function? – Raymond Camden Jun 17 '13 at 18:39
  • Ray - thanks for the help. Using "any" for type functions exactly the same as "string" (no errors but same string value). When I call toBinary(body) I get an error telling me it must be base-64 encoded. When I use toBinary(toBase64(body)) I believe I end up with a binary (no errors thrown), but am not sure what to do with it at that point. If I save the file using cffile as a .gz and try to open it on a Mac creates a .cpgz file that still won't open. When I take the binary and put it through the toString() function I get a string that is the string that went into the function. – scoDubblT Jun 17 '13 at 21:01
  • I also tried looping over a list of valid encodings and tried charsetDecode / charsetEncode with all valid encoding types with no success. Any other thoughts? – scoDubblT Jun 17 '13 at 21:02
  • Hmm, I'm sorry, I really don't know. I do think Miguel has a point, the web server should possibly be handling it. Outside of that I don't know. If you had a way for me to test this easily, I'd give it a shot. – Raymond Camden Jun 22 '13 at 21:27

3 Answers3

3

Just to add some additional input here, I did submit a bug request as attempting to change the web.xml configuration file did not initially work for me. I had added additional entries into configuration file for the GZIP decoding and instead what needed to be done was to add to the existing entries the parameter value for the GZIP encoding filters.

The original-unchanged file in web.xml should show entries such as this, found under the servlet named CFRestServlet:

<init-param>
    <param-name>com.sun.jersey.spi.container.ContainerRequestFilters</param-name>
    <param-value>coldfusion.rest.servlet.CFUriConnegFilter;coldfusion.rest.servlet.CFRequestFilter</param-value>
</init-param>
<init-param>
    <param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name>
    <param-value>coldfusion.rest.servlet.CFResponseFilter</param-value>
</init-param>

In order to enable the gzip filters, update these two parameters to have them to appear this way instead:

<init-param>
    <param-name>com.sun.jersey.spi.container.ContainerRequestFilters</param-name>
    <param-value>coldfusion.rest.servlet.CFUriConnegFilter;com.sun.jersey.api.container.filter.GZIPContentEncodingFilter;coldfusion.rest.servlet.CFRequestFilter</param-value>
</init-param>
<init-param>
    <param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name>
    <param-value>coldfusion.rest.servlet.CFResponseFilter;com.sun.jersey.api.container.filter.GZIPContentEncodingFilter</param-value>
 </init-param>

As you'll see, you simply need to add the "com.sun.jersey.api.container.filter.GZIPContentEncodingFilter" as another value to the semi-colon separated list of values. Once you've made the changes, restart your CF server and then your REST based services will properly and automatically decode any GZip encoded data they receive.

For reference, my bug request can be read here: https://bugbase.adobe.com/index.cfm?event=bug&id=3694176

Thanks.

2

If I understand your problem correctly, this can be done with GZIPContentEncodingFilter

In short CF's rest support is built upon JERSEY APIs. When a request comes to a rest endpoint (defined in the URL), a series of jersey filters execute before invoking the actual function. This is where this filter would execute and handle GZIP compression for you.

You may configure only the request filter (In case the library is not expecting a gzipped response back). Just add following in web.xml and hopefully will be done.

 <init-param>
         <param-name>com.sun.jersey.spi.container.ContainerRequestFilters</param-name>
         <param-value>com.sun.jersey.api.container.filter.GZIPContentEncodingFilter</param-value>
</init-param>

CF already has one filter added for handling *.json & *.xml requests.

HTH, Chandan Kumar

Chandan Kumar
  • 361
  • 1
  • 8