Failing to get API data from WebSocket

Hi

Which Node can send http request like packets to a ws://...../ url
or direction to replicate html ajax into node red

I have a flow with a simple function,
HTTP request node sends POST with JSON credentials
msg returned has a header with _session_id
use switch and function nodes to add headers for cookies and data types
POST all this to HTTP request node ( to instruct start sending events )
and websocket out (connecting to API server on corrrect path)
tried GET to websocket no change

In wireshark I get protocol switch 101 if i send ws:// to http://
but I dont see the websocket traffic at all and the socket closes immediately
If I look closely at wireshark for attached html I see the ws://192..../wsapi GET
but I cant replicate this in node-red as WS node traffic doesnt show in wireshark
AT all

If I run the html scripts I am trying to replicate in browser
everything works
tried to use UI builder to put that HTML in but later there will be issues with cross-domain and HTTPS requirements

[{"id":"21b264d9.35577c","type":"function","z":"b88045d9.169908","name":"","func":"//var bs = flow.set('headers', msg.headers);\n//msg = \"\";\nvar ws_Key = msg.payload._Key;\nvar bs_call = flow.get('headers.bs-session-id');\nvar hd_call = flow.get('headers.Cookie');\nmsg.headers = {};\nmsg.headers['Connection'] = 'Upgrade',\nmsg.headers['Upgrade'] = 'websocket',\nmsg.headers['Sec-WebSocket-Version'] = '13',\nmsg.headers['bs-session-id'] = bs_call,\nmsg.headers['Sec-WebSocket-Key'] = ws_Key,\nmsg.headers['Sec-WebSocket-Extensions'] = 'permessage-deflate; client_max_window_bits',\nmsg.headers['Cookie'] = hd_call;\nvar j = \"GET\";\nmsg.method = j;\n//var i = '192.168.0.109/wsapi';\n//msg.url =i;\n//msg.headers[''] = '';\nmsg.payload = 'bs-session-id' + '=' + bs_call;\n//msg.statusCode = \"\";\n//node.send(msg);\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":760,"y":420,"wires":[["99045d0d.b2bfc","132534d1.93139b"]]},{"id":"76f3973d.ff3dc8","type":"change","z":"b88045d9.169908","name":"Cookie","rules":[{"t":"set","p":"headers.Cookie.WebLoginHandle","pt":"msg","to":"1599147251652","tot":"str"},{"t":"set","p":"headers.Cookie.io","pt":"msg","to":"vATAy6Qfvd-zamHCAAAB","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":730,"y":340,"wires":[["c069aaea.685a98"]]},{"id":"99045d0d.b2bfc","type":"debug","z":"b88045d9.169908","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":930,"y":420,"wires":[]},{"id":"c069aaea.685a98","type":"objectid","z":"b88045d9.169908","name":"","selectedProperty":"_Key","x":750,"y":380,"wires":[["21b264d9.35577c"]]},{"id":"d880e506.743918","type":"inject","z":"b88045d9.169908","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":440,"y":300,"wires":[["5e2b4adc.c8c1c4"]]},{"id":"e8b8c177.73141","type":"http request","z":"b88045d9.169908","name":"","method":"POST","ret":"obj","paytoqs":"query","url":"http://192.168.0.109/api/login","tls":"","persist":true,"proxy":"","authType":"","x":730,"y":300,"wires":[["76f3973d.ff3dc8","49f12eda.0e198"]]},{"id":"5e2b4adc.c8c1c4","type":"change","z":"b88045d9.169908","name":"Sign In","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\t  \"User\": {\t    \"login_id\": \"admin\",\t    \"password\": \"Admin123\"\t  }\t}","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":590,"y":300,"wires":[["e8b8c177.73141"]]},{"id":"132534d1.93139b","type":"websocket out","z":"b88045d9.169908","name":"","server":"","client":"a7dfc535.c07308","x":830,"y":460,"wires":[]},{"id":"fdce8ffb.71638","type":"debug","z":"b88045d9.169908","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1110,"y":380,"wires":[]},{"id":"57fd0f16.5c0bc","type":"function","z":"b88045d9.169908","name":"","func":"var bs = flow.set('headers', msg.headers);\nvar bs_call = flow.get('headers.bs-session-id');\nvar hd_call = flow.get('headers.Cookie');\nmsg.headers = {};\nmsg.headers['bs-session-id'] = bs_call,\nmsg.headers['Content-Type'] = 'application/json',\nmsg.headers['Cookie'] = hd_call,\nmsg.headers['X-Requested-With'] = 'XMLHttpRequest';\n//msg.headers[''] = '';\nmsg.payload = 'bs-session-id='+bs_call;\nvar j = \"POST\";\nmsg.method = j;\nvar i = 'http://192.168.0.109/api/events/start';\nmsg.url =i;\nnode.send(msg);\n\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":940,"y":340,"wires":[["4063d1d5.5fa49","98033d4b.ac8c6"]]},{"id":"4063d1d5.5fa49","type":"http request","z":"b88045d9.169908","name":"","method":"use","ret":"txt","paytoqs":"ignore","url":"","tls":"","persist":true,"proxy":"","authType":"","x":950,"y":380,"wires":[["fdce8ffb.71638"]]},{"id":"49f12eda.0e198","type":"change","z":"b88045d9.169908","name":"Cookie","rules":[{"t":"set","p":"headers.Cookie.WebLoginHandle","pt":"msg","to":"1599147251652","tot":"str"},{"t":"set","p":"headers.Cookie.io","pt":"msg","to":"vATAy6Qfvd-zamHCAAAB","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":940,"y":300,"wires":[["57fd0f16.5c0bc"]]},{"id":"98033d4b.ac8c6","type":"debug","z":"b88045d9.169908","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1090,"y":340,"wires":[]},{"id":"a7dfc535.c07308","type":"websocket-client","z":"","path":"ws://192.168.0.109:/wsapi","tls":"","wholemsg":"true"}]
<html>
  <head>
    <meta http-equiv="content-type" content="text/html; charset=windows-1252">
    <title>API 2</title>
  </head>
  <body>
    <div>
      <button id="loginBtn">Login</button> </div>
    <script src="https://code.jquery.com/jquery-3.2.1.min.js" integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4="crossorigin="anonymous"></script>
    <script>
		$(document).ready(function(){
			var API_HOST = 'https://192.168.0.104:443',
				WS_HOST = 'wss://192.168.0.104:443',
				LOGIN_API_URI = API_HOST + '/api/login',
				WS_URI = WS_HOST + '/wsapi',
				WS_EVENT_START_URI = API_HOST + '/api/events/start';
			
			$('#loginBtn').load(function(){
				var loginData = {
					'User':{
						'login_id': "admin",
						'password': "Admin123"
					}				
				};				
						
			$.ajax({
					url: LOGIN_API_URI,
					type: 'POST',
					dataType: 'json',
					data: JSON.stringify(loginData),
					contentType: 'application/json',
					success: function(data, textStatus, request){						
						var bsSessionId = request.getResponseHeader('bs-session-id'),							
							ws = new WebSocket(WS_URI);
							
						ws.onopen = function(){  
							ws.send('bs-session-id' + "=" + request.getResponseHeader('bs-session-id'));
							setTimeout(function(){postAPI2()}, 1000)
	
							function postAPI2(){$.ajax({
								url: WS_EVENT_START_URI,
								type: 'POST',
								dataType: 'json',								
								contentType: 'application/json',
								beforeSend: function(request) {
									request.setRequestHeader("bs-session-id", bsSessionId);
								},
								success: function(data, textStatus, request){						
									console.log(data, textStatus, request);
								},
								error: function(err){
									console.log(err);
								},
							});     
						     }  
						};  
						
						ws.onmessage = function (event) {
							console.error(event);
						};
					},
					error: function(err){
						console.log(err);
					},
				});       
			});
		});
	</script>
  </body>
</html>

GET /wsapi HTTP/1.1
Host: 192.168.0.109
Connection: Upgrade
Pragma: no-cache
Cache-Control: no-cache
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36 Edg/87.0.664.41
Upgrade: websocket
Origin: http://192.168.0.109
Sec-WebSocket-Version: 13
Accept-Encoding: gzip, deflate
Accept-Language: en-GB,en;q=0.9,en-US;q=0.8

Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits

HTTP/1.1 101 
Upgrade: websocket
Connection: upgrade

X-Content-Type-Options: nosniff
X-XSS-Protection: 1
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: SAMEORIGIN
Date: Tue, 24 Nov 2020 19:09:56 GMT

.....$..T	....YtQ..
.i..7l....%......h.......n.......$.%..R..........T%+.j..X49?.$.d..........%..*...e&...L..5511.0.42T.AH..$.........Hw..K.....

Sorry, maybe I'm tired but I can't understand what you are trying to do.

That doesn't seem to make sense. When you start a websockets connection, it starts automatically as an http(s) connection and then upgrades to a ws(s) if it can. Websockets can be blocked by proxies and content aware firewalls in some cases so an upgrade is not always possible.

So you can send custom headers to the initial handshake in a websocket connection. However, once the upgrade happens, no further custom headers are allowed. It is for this reason that you cannot do proper session handling over websockets, if you need to keep checking the session validity, you need to use the websocket data rather than headers.

The connections are all resident on the same server so the address can be localhost as an example or the same address

Lets say i have 5 browsers connected to my nginx site if they all initiate an upgrade to websocket all traffic is not broadcast to all 5 but along to the individual hosts

I need to start a http handshake then once authenticated upgrade to ws .
If I try using the core ws node then i get all the up to the upgrade but the nginx server sends 1 websocket packet and the node red ws node dont open port and accept traffic

How does ws identify which browser to send traffic to

Or i am looking for advise on which other route to replicate the ajax in the working html page which is using ws nodejs module

I think this might be on the backlog for Node-RED? https://trello.com/c/nx4islGu/80-ws-customise-options-on-outbound-ws-connections

If you use uibuilder, it supports the insertion of a Socket.IO middleware function that will allow you to do authentication at the point of the initial http connection.

It seems exactly like that request . I couldnt see if anything came of the initial thread

Do you somewhere to find info on the socket.io and ui builder option

It is still on the backlog. There is the setting for incoming requests of course but not outgoing.

uibuilder doesn't do outgoing requests either. Check the security branch on GitHub which has more documentation on websocket security for how it works.

Thank you Julian

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.