Illegal character in http request

I've got a device I'm trying to write a driver for, but I'm running into an issue. I have to use a packet sniffer to figure out the api so I'm running a little blind. Further, the there are some, what I consider, odd parts of the api. Some requests are fully URL encoded; some are partially; and some are not at all. It seems rather random to me.

Where this causes me a problem is here. I have one request where the literal string works in a web browser just fine, but if I try to do it with httpGet, I get an error.

def setupQueue()
{
    logDebug("setupQueue()")
    params=[
        uri: "http://${ipAddress}:80/api/event/modifyQueue?queueId=&subscribe=[{\"path\":\"settings%3A/mediaPlayer/mute\",\"type\":\"item\"},{\"path\":\"settings%3A/mediaPlayer/mute\",\"type\":\"rows\"}]&unsubscribe=[]",
        headers: ["Accept":"application/json"],
        timeout:10
        ]
    try{
        httpGet(params){response->
            if(response.status!=200){
                logError("Error setting up queue ${response.status}")
            } else {
                logDebug(response.data)
            }
        }
    }catch(e){
        logError("Error ${e.getMessage()}")
    }
}

I keep getting this error:

Illegal character in query at index 66: http://XXX.XXX.X.XXX:80/api/event/modifyQueue?queueId=&subscribe=[{"path":"settings%3A/mediaPlayer/mute","type":"item"},{"path":"settings%3A/mediaPlayer/mute","type":"rows"}]&unsubscribe=[]

If I copy the string from the error message, and past it into a web browser, I get a perfect response.

This seems to be directly pointing to the fact that it is not URL encoded because it is complaining about the "{". If I encode it, the device responses that it is an illegal request.

I can't find a way around this one. I tried webSocket, but I honestly don't understand what I'm doing there and just kept getting an error that it was expecting a 101 response but got a 200 response.

Any clarity on this would be appreciated.

Maybe something like this would help. It takes the hand encoding out of the equation:

    def query = [[path:"settings:/mediaPlayer/mute", type: "item"], [path: "settings:/mediaPlayer/mute", type: "rows"]]
    query = groovy.json.JsonOutput.toJson(query)
    logDebug ("raw json = ${query}")
    
    query = java.net.URLEncoder.encode(query, "UTF-8")
    logDebug ("encoded query = ${query}")
    
    query = "http://${ipAddress}:80/api/event/modifyQueue?queueId=&subscribe=" + query + "&unsubscribe=[]"
    logDebug ("full URL = ${query}")

I went down that same route. The problem is that the server won't accept a fully encoded request. If I do that, I get a response from the server that the request is invalid.

That's odd. If your remote server rejects an encoded request, and your local server (Hubitat) can't send an un-encoded one, then you're stuck.

I'd recommend doing your test from the browser that works and using either wireshark to locally sniff the actual traffic going to the remote server or postman-echo to remotely inspect what the browser is actually sending.

And then keep poking on the Hubitat side to assemble a request that is only as encoded as what the remote server seems to be accepting from the browser.

What is the remote server? Any chance its source is open so you can debug where it is breaking down on that side?

Not sure if this is useful, but if I copy out the the URL out into Notepad++, and assuming your masking of the IP address is accurate to the number of digits, Notepad++ indicates that character 66 is actually the first square bracket, not the curly brace. From what I've seen the encoding for these is meant to be %5b and %5d.

I believe if you paste and unencoded URL into the address bar and hit go, at least Chrome and maybe edge will display the encoded version as the page loads. Might be interesting to see what comes out in the address bar when you do successfully open them in a browser.

Interesting point I may have missed. I was assuming a zero index for the error report. That would put it on the brace, but a one index would put it on the square bracket.

I'll play with that and see what comes of it.

1 Like

This server is actually a Grace Digital Mondo Elite internet clock radio. There is nothing I could find publicly about the code or api, so I was capturing the packets from their own android app and viewing them in wire shark. That is how I found the string to send in the first place.

I was hoping there might be a way to brute force this and send the appropriate packets in some kind of raw form to bypass the checks in httpGet.

I did a little test, and it is definitely complaining about the '{'. I replaced it with code for url encoding, and it got transmitted fine, but the server rejected the request because it didn't know what it was.

Unless I can tell httpGet to not check for invalid characters, or I can find a way to send raw packets, I think I'm stuck.

You could try setting the contentType for the request as 'application/x-www-form-urlencoded'

You could also try something like this: [Solved] Pushover Notification with Image

1 Like