Translation of Curl command to HTTP Request

Hi,

Looking for some help, Trying to talk to a GL.iNet Router and having problems. I am just not grasping this - it should be so simple!!

I have been trying to convert a Curl command (which does work) to an HTTP Request for the last few days and am rapidly losing my fingerprints!

POST gets me a 200 response, but the password is not being read (among other diagnostics) "{"code":-1,"msg":"Token is null"}"

curl <IPADDRESS>/api/router/login -d "pwd=XXYYZZAABB"

Would really be grateful for some help.

TIA,
Colin J

I know nothing but have always understood that curl cannot be replicated as a URL request/post/get

What does this flow output?
(NOTE: change the http/https and IP in the function as required)

[{"id":"4816c6bb62da7b02","type":"inject","z":"b872cb4b.5a6448","name":"Click me","props":[],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":1260,"y":120,"wires":[["4816c6bb62da7b03"]]},{"id":"4816c6bb62da7b03","type":"function","z":"b872cb4b.5a6448","name":"","func":"//original curl:  \n//\n//curl http://1.2.3.4/api/router/login -d \"pwd=XXYYZZAABB\"\n\nmsg.method = \"post\";\nmsg.url = \"http://1.2.3.4/api/router/login\";\nmsg.payload = `pwd=XXYYZZAABB`;\nmsg.headers = null;\nmsg.cookies = null;\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1440,"y":120,"wires":[["4816c6bb62da7b04"]]},{"id":"4816c6bb62da7b04","type":"http request","z":"b872cb4b.5a6448","name":"","method":"use","ret":"txt","paytoqs":"ignore","url":"","tls":"","persist":false,"proxy":"","authType":"","x":1620,"y":120,"wires":[["4816c6bb62da7b05"]]},{"id":"4816c6bb62da7b05","type":"debug","z":"b872cb4b.5a6448","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1780,"y":120,"wires":[]}]

Assuming curl works, this response suggests curl is sending more in the http request that you believe (something like a header or cookie that you will need to add to the msg for the node-red http request node). Do you have wireshark installed? Or perhaps postman? (something to fully inspect the request and the response outside of node-red)

Also, see these posts for similar / related tips and clues...

HTTP Toolkit ?

1 Like

It is a request for a token to use with a REST API and the response comes in the form

{"code":0,"token":"1122334455667788aabbccddeeff"}

Documentation
I had edited my curl call above to protect the innocent - the call is correctly constructed and does work. It is just that I am doing everything manually at the moment, each time I make the call, or reset the router, the token changes.

I have been looking in the Browser Developers Tools to see what is being sent, but can't quite get the complete picture and so will try the tools suggested. Wireshark overwhelms me for the very infrequent use I use it, so will try HTTP Toolkit first.

Other than that, I will try to use the function node to fetch the data.

I am just trying to understand what is going on and, after reading other posts, I see that the HTTP Request is suggested as an alternative to Curl in many instances. Perhaps, this can only be done by Curl.

Eventually, I hope to use Node-RED to monitor the signal strength direct off the GSM Modem to help me point the (directional) antenna in the right direction.

Thank you all for your help. It is greatly appreciated.

Are you saying the flow I wrote gets you a code 0 and a token value?

If so, then I suspect you simply keep hold of the token and use that as a header in subsequent HTTP requests to other parts of the API.

Similar to the thread I linked to before.

This is the response from your code

payload: "{"msg":"password missing","code":-5}"

So, your code changes the response, but see that you have some other messages in there. Will look and analyse.

Just started to look at HTTP Toolkit to intercept Curl command and your flow.

EDIT: Looks like the headers may be the key and will try to adapt @Steve-Mcl flow to contain them. May take a while as I have other duties I need to do through the day.

Thank you Guys!!

Between @Steve-Mcl and @Andrei suggestions I have got this working, it is the Headers causing the problem

Changed the msg.headers = null; to msg.headers = {'content-type':'application/x-www-form-urlencoded'} and all now works!!

As usual the support from the forum is excellent.

I see @cymplecy suggests that 'curl cannot be replicated as a URL request/post/get'. Is this so for any particular circumstances?

Thank you again!

2 Likes

He also said that he knows nothing :slight_smile:

3 Likes

:rofl:I saw that, but there is usually 'no smoke without a fire' so thought you may have come across an instance.

Until today, I've never come across an instance where a curl could be replaced by something else

I don't understand http at all :slight_smile:

1 Like

So far, I haven't come across any circumstances where I couldn't use the http request to replace curl. That said, curl has a LOT of options, I'm certain there will be something but I don't know what.

1 Like

Which bit of "I know nothing" are you lot having trouble with? :slight_smile:
Your arguing with an http idiot :slight_smile:

2 Likes

So, managed to get the information I was after from my GL.iNET Router.

Below is a flow that gets the Security Token and then you can GET or POST a URL to the router to obtain the client list and cell information. If it is of use to anyone, well, here it is...

[
    {
        "id": "0f814aab11ca6a59",
        "type": "inject",
        "z": "362ac6b30a7e45bc",
        "name": "Click me",
        "props": [],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payloadType": "str",
        "x": 140,
        "y": 320,
        "wires": [
            [
                "360590ca88c2741e"
            ]
        ]
    },
    {
        "id": "360590ca88c2741e",
        "type": "function",
        "z": "362ac6b30a7e45bc",
        "name": "Curl token",
        "func": "//original curl:  \n//\n//curl http://1.2.3.4/api/router/login -d \"pwd=XXYYZZAABB\"\nmsg.headers = {}; \n\nmsg.method = \"post\";\nmsg.url = \"http://<IP_ADDRESS>/api/router/login\";\nmsg.payload = \"<PASSWORD>\";\nmsg.headers[\"Content-Type\"] = \"application/x-www-form-urlencoded\";\nmsg.cookies = null;\n\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 370,
        "y": 320,
        "wires": [
            [
                "af82bb868566726f"
            ]
        ]
    },
    {
        "id": "af82bb868566726f",
        "type": "http request",
        "z": "362ac6b30a7e45bc",
        "name": "",
        "method": "use",
        "ret": "txt",
        "paytoqs": "ignore",
        "url": "",
        "tls": "",
        "persist": false,
        "proxy": "",
        "authType": "",
        "credentials": {},
        "x": 550,
        "y": 320,
        "wires": [
            [
                "ea345df5628fa288"
            ]
        ]
    },
    {
        "id": "ea345df5628fa288",
        "type": "function",
        "z": "362ac6b30a7e45bc",
        "name": "global.curlToken",
        "func": "let curlToken = msg.payload;\nlet curlTest = msg.payload.slice(8, 9);\nmsg.test = curlTest;\n\nif (curlTest === \"0\"){\n        curlToken = curlToken.slice(19, 51);\n        global.set('curlToken', curlToken);\n        msg.payload = \"Token OK\";\n} else {\n    msg.payload = \"Token Error\";\n}\n\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 740,
        "y": 320,
        "wires": [
            [
                "c402da04521e4baa"
            ]
        ]
    },
    {
        "id": "7fa01b1b8e12231b",
        "type": "http request",
        "z": "362ac6b30a7e45bc",
        "name": "",
        "method": "use",
        "ret": "txt",
        "paytoqs": "ignore",
        "url": "http://<IP_ADDRESS>/{{{topic}}}",
        "tls": "",
        "persist": false,
        "proxy": "",
        "authType": "",
        "credentials": {
            "user": "",
            "password": ""
        },
        "x": 550,
        "y": 360,
        "wires": [
            [
                "78aa4714ee584214"
            ]
        ]
    },
    {
        "id": "c402da04521e4baa",
        "type": "debug",
        "z": "362ac6b30a7e45bc",
        "name": "",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 1030,
        "y": 360,
        "wires": []
    },
    {
        "id": "3995f987df0f97bc",
        "type": "inject",
        "z": "362ac6b30a7e45bc",
        "name": "",
        "props": [
            {
                "p": "topic",
                "vt": "str"
            },
            {
                "p": "method",
                "v": "get",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "api/client/list",
        "x": 130,
        "y": 360,
        "wires": [
            [
                "ea6f81fcf7ea3965"
            ]
        ]
    },
    {
        "id": "ea6f81fcf7ea3965",
        "type": "function",
        "z": "362ac6b30a7e45bc",
        "name": "Curl token",
        "func": "msg.headers = {}; \n\nlet curlToken = global.get('curlToken');\n\nmsg.headers[\"Content-Type\"] = 'application/x-www-form-urlencoded';\nmsg.headers[\"Authorization\"] = curlToken;\n\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 370,
        "y": 360,
        "wires": [
            [
                "7fa01b1b8e12231b"
            ]
        ]
    },
    {
        "id": "c4fb67c8a0f07f31",
        "type": "function",
        "z": "362ac6b30a7e45bc",
        "name": "Curl token",
        "func": "msg.headers = {}; \n\nlet curlToken = global.get('curlToken');\n\nmsg.headers[\"Content-Type\"] = \"application/x-www-form-urlencoded\";\nmsg.headers[\"Authorization\"] = curlToken;\nmsg.payload = \"modem_id=1&bus=1-1.2\";\n\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 370,
        "y": 400,
        "wires": [
            [
                "1220b9f446f8bb67"
            ]
        ]
    },
    {
        "id": "e09431020a17d4eb",
        "type": "inject",
        "z": "362ac6b30a7e45bc",
        "name": "",
        "props": [
            {
                "p": "topic",
                "vt": "str"
            },
            {
                "p": "method",
                "v": "post",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": true,
        "onceDelay": 0.1,
        "topic": "api/modem/cells/get",
        "x": 160,
        "y": 400,
        "wires": [
            [
                "c4fb67c8a0f07f31"
            ]
        ]
    },
    {
        "id": "78aa4714ee584214",
        "type": "json",
        "z": "362ac6b30a7e45bc",
        "name": "",
        "property": "payload",
        "action": "",
        "pretty": false,
        "x": 710,
        "y": 360,
        "wires": [
            [
                "c402da04521e4baa"
            ]
        ]
    },
    {
        "id": "1220b9f446f8bb67",
        "type": "http request",
        "z": "362ac6b30a7e45bc",
        "name": "",
        "method": "use",
        "ret": "txt",
        "paytoqs": "ignore",
        "url": "http://<IP_ADDRESS>/{{{topic}}}",
        "tls": "",
        "persist": false,
        "proxy": "",
        "authType": "",
        "credentials": {
            "user": "",
            "password": ""
        },
        "x": 550,
        "y": 400,
        "wires": [
            [
                "fcd29dc0e286e61e"
            ]
        ]
    },
    {
        "id": "fcd29dc0e286e61e",
        "type": "json",
        "z": "362ac6b30a7e45bc",
        "name": "",
        "property": "payload",
        "action": "",
        "pretty": false,
        "x": 710,
        "y": 400,
        "wires": [
            [
                "9c0b88b96b6039d3"
            ]
        ]
    },
    {
        "id": "9c0b88b96b6039d3",
        "type": "function",
        "z": "362ac6b30a7e45bc",
        "name": "",
        "func": "let rssi = msg.payload.cells[0].rssi\nmsg.payload = msg.payload.cells[0].rssi;\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 860,
        "y": 400,
        "wires": [
            [
                "c402da04521e4baa"
            ]
        ]
    }
]

Thank you everyone for your help!

EDIT: Modified Flow with thanks to @UnborN and @E1cid for making it easier and less convoluted!!

Hi .. thumbs up for finding a solution :+1:
but what are those unnecessary code you are doing in your "Load Headers" Functions ?
(creating a JSON string with escaping double quotes, concatenation of strings and json.parse) :innocent:

you can simply do

msg.headers["Content-Type"] = "application/x-www-form-urlencoded";
msg.headers["Authorization"] = curlToken;
1 Like

Tried this and I get "TypeError: Cannot set property 'Content-Type' of undefined" . I will have a play as that looks a lot easier if I can get it to work.

Spent many hours on my convoluted solution, couldn't get the curlToken into the Authorization: header.

you need to declare msg.headers as an object
add

msg.headers = {}; 

before the other references to msg.headers.

1 Like

Oh WOW! Thank you!! It is so easy when you know how!!

Not sure I would ever have sussed that out!!

Modified flow posted above.