Accepting Scripted REST Connections for Weird Content-Types

PHOTO EMBED

Mon Feb 01 2021 21:22:08 GMT+0000 (Coordinated Universal Time)

Saved by @nhord2007@yahoo.com #servicenow #content #type #plain #text

/* This will come in the body at XML but the header will be text/plain, which is why  
all this is happening manually to get this read from the stream.  
*/  
var reqHeaders = request.headers;
gs.info("CPSNS: reqHeaders content-type" + reqHeaders['content-type']);
if (reqHeaders['content-type'] == "text/plain; charset=UTF-8") {
    var stream = request.body.dataStream;
    var reader = new GlideTextReader(stream);
    var input = "";
    var ln = "";
    while ((ln = reader.readLine()) != null) {
        input += ln;
    }
    gs.info("CPSNS: SUB" + input);
} else {
    var body = {};
    var data = request.body.data;

    gs.info("CPSNS: req.body data" + data);

}
content_copyCOPY

In an interesting coincidence, I recently had to solve this issue in my own Travel Tracker app (as seen on a number of Live Coding Happy Hour episodes). Just today, someone in the Developer Program asked the same thing so I thought I would document it for posterity. What happens when an incoming connection you don’t control (such as a webhook) isn’t using application/json or application/xml as the Content-Type on the HTTP transaction? I demonstrated this on the July 7 2017 Live Coding Happy Hour with Andrew Barnes aka ajb. I had been having trouble with a webhook that should have been hitting my Scripted REST API endpoint but I had no evidence of it ever executing. After examining the webhook transactions with the help of Mockbin I realized that the webhook sends requests with Content-Type set to text/plain even though the body is XML. Because the accept types were set to JSON or XML, this never even completed the handshake as a valid transaction so it never happened. That seemed like the end of it until I tried to hook it up. I allowed the MIME type into the transaction but then I had a new problem. I began getting errors when I tried to use request.body.data to actually access the XML. By adding text/plain to the allowed Content-Type, attempts to access request.body.data resulted in this error: com.glide.rest.domain.ServiceException: Server error: attempt to access operations that are not allowed when request content is not one of ServiceNow default content types In fact, all I was doing with the XML was passing to gs.xmlToJSON() but even trying to get the dataString object would give an error like above. I don’t know if this is the only solution to the problem but this is a way I was able to get the incoming body. /* This will come in the body at XML but the header will be text/plain, which is why all this is happening manually to get this read from the stream. */ var stream = request.body.dataStream; var reader = new GlideTextReader(stream); var input = ""; var ln= ""; while((ln = reader.readLine()) != null) { input += ln; } Save It’s a bit roundabout but this will get around those built in errors caused by the more permissive Content-Type setting. The system can’t guarantee that it can marshall it into a data structure so it refused to do the request.body.data call for it. It will let you do a Reader on the stream so that it was you have to do. It is extra code but when you are done, you will have the full payload of the HTTP body no matter what the Content-Type was or the structure of the data.

https://developer.servicenow.com/blog.do?p