Content type: text/xml vs. application/x-www-form-urlencoded

We have a service that can successfully receive an http posting when the content type is application/x-www-form-urlencoded, but fails when the content type is text/xml. This service has an input object (contentStream) and uses custom Java code to extract the incoming content from the pipeline as key/value pairs.

I’ve tried using the canned service bytesToString but it doesn’t work.

What is the best way to receive a stream of data?

When the content type is text/xml, the Integration Server will assume that that body of the HTTP POST is an XML message so it will automatically parse the XML and place an XML node object in the pipeline. Therefore, your service should have an input variable called node and you can then call services from WmPublic/pub.xml on that object.

Note: if your client wants to post an XML message to you by using content type application/x-www-form-urlencoded, you can also have the IS recognize the presence of the XML and give you a parsed XML node. The trick here is to send the XML message in an HTTP variable called $xmldata.

  • Percio

Thanks very much for the quick response. I was able to use xmlNodeToDocument to handle the text/xml request using a service with an input of type object (named contentStream). Could you elaborate on how I implement the trick you mentioned? I’m not familiar with what you mean by “HTTP variable called $xmldata”.

Finally, is there a good way to manage figuring out what type of request is incoming? It would be difficult at this point to have the requests with varying content types directed to different services. The code right now is trying one method and then the other if the first fails.

Thanks again.

The reason why using xmlNodeToDocument works is because whether you declare an input variable called node or not, the node object will still exist in the pipeline at run-time. You should declare the node object as input anyway for clarity.

Regarding the $xmldata “trick”, when you transmit data over HTTP using content type application/x-www-form-urlencoded, the payload comes across in name/value pairs, correct? All I’m saying is that if one of the values you’re transmitting is an XML message, you should name it $xmldata. The IS content handler will automatically parse the XML and place an XML node in the pipeline. Search WMUsers for the string $xmldata and you should find some useful posts.

  • Percio

One more thing regarding your statement:

Why do you need Java code to extract the key/value pairs? The IS content handler does this automatically. Try this:

  1. Create an empty flow service
  2. Add a savePipeline step and set $name to let’s say test.
  3. Save the service
  4. Open a browser and type a URL in the address bar to invoke the service but add some name value pairs at the end of the URL. Example:
    http://localhost:5555/invoke/percio.testing/testService?msgPart1=Hello&msgPart2=World
  5. Hit return to invoke the service
  6. Go back to the service and remove/disable the savePipeline step
  7. Add a restorePipeline step and set $name to test.
  8. Save and run the service

You should see variables in your pipeline that correspond to the name/value pairs in the URL you created.

  • Percio

The custom Java code I mentioned was used because it was the method used by my collegue on another project and it worked so there was no reason to question it until we started receiving the text/xml content. But you’ve given me some techniques to try and I’ll post the results.

Thanks very much for your help!

This may be why the custom Java was written. The data we’re receiving does not appear to be in key/value format; it’s just data. The sniffer indicates the following is being received:

POST /invoke/myservice.Receiver/Service HTTP/1.1
Content-type: application/x-www-form-urlencoded
Authorization: Basic xxxxxxxxxxxxxxxxxxx
User-Agent: Jakarta Commons-HttpClient/2.0final
Host: localhost:5558
Content-Length: 8339

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE"

In that case, the content-type is simply wrong. XML is not a form.

It would seem the use of a content type that doesn’t match the content is what is contributing to the confusion.

As Rob stated, it seems that the data is XML, not FORM variables. In that case content-type is incorrect. To properly receive the msg, set content-type to text/xml.

Thanks. As suggested, I’ve modified the test client to POST as text/xml. This makes receiving the XML easy, but I have a new issue. The stream returned to the client now seems to be the contents of the pipeline instead of just the outgoing XML. My service is designed to build the return XML in a string named OutgoingXML. This string is returned to the client using the simple template %value OutgoingXML%.
When the test client posts as content type “application/x-www-form-urlencoded” I get back what I expect, something that begins with:
<?xml version="1.0" ?> <STATUS

But when I POST as text/xml, I get:
<?xml version="1.0" encoding="UTF-8"?>


3.0
<?xml version="1.0" ?> <STATUS

What is the correct way to return XML to the client?

Again, thanks for all the help!

Use WmPublic/pub.flow:setResponse

Thank you , thank you, THANK YOU!

Not sure if the thread is still active here’s my question:

Is it possible to:

  1. XML posted to IS in HTTP body, not query variable or form etc.

  2. Flow service receives the XML as string (or byte[]), BEFORE it’s parsed to a node.

What content type and built-in service should I use to get the HTTP body as string/byte[] without parsing? The XML will not be processed in IS. It is immediately passed to some external app so parsing it into a DOM tree is simply waste of time.

In addition, if I can get entire HTTP body without assuming any content type then I can also use HTTP to pass in any data type, e.g. serialized Java objects, C structs, etc.

Yes

No

Well, actually the answer to the second question should be Yes as well…

You have several options:

  1. In the HTTP POST just use a Content-Type that the IS does not know. A good choice would be application/octet-stream. The IS will then put the HTTP body into the pipeline as an Object of type java.io.InputStream with the name “contentStream” and you can read the contents in binary format from the stream. (Should not be much harder than working on a byte[].)

  2. If you can’t influence the HTTP client’s Content-Type, then you can “de-register” the Integration Server’s content handler for text/xml. Afterwards the IS will no longer “recognize” the Content-Type text/xml and will give you a “contentStream” object for that Content-Type as well.

All you need for this is a Java Service with the following code:


ServerAPI.removeContentHandler("text/xml");

(Under “Imports” add the line
com.wm.app.b2b.server.ServerAPI
)

and define this Service as a “Startup Service”, so it gets executed whenever the IS starts. However, be aware that the IS will then do no XML parsing of incoming requests anymore… :wink:

Lanzelot