Flask-SocketIO: Cannot connect to a namespace - socket.io

I have problems connecting to my server via Websockets while using Flask-SocketIO. Everything works if I don't specify a custom namespace, but if I want to connect to a namespace I cannot connect. What am I doing wrong?
I made a small scratch program, which shows my problem:
### removed to make the post less long, see below ###
I'm pretty sure I connect the client wrong. But I don't know how to do it right. I looked through the SocketIO Client documentation, but couldn't find help.
EDIT:
To make it clearer, here is an updated version with just one socket:
from flask import Flask
from flask_socketio import SocketIO
app = Flask(__name__)
socketio = SocketIO(app)
#socketio.on("connect", namespace="/test")
def handle_connect():
print("heureka!")
return True
#app.route('/')
def index():
return """
<!DOCTYPE HTML>
<html>
<head>
<title>Flask-SocketIO Test</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/3.0.4/socket.io.js" integrity="sha512-aMGMvNYu8Ue4G+fHa359jcPb1u+ytAF+P2SCb+PxrjCdO3n3ZTxJ30zuH39rimUggmTwmh2u7wvQsDTHESnmfQ==" crossorigin="anonymous"></script>
<script type="text/javascript" charset="utf-8">
var socket1 = io("http://127.0.0.1:5000/test");
socket1.on("connect", function() {
console.log("yay!")
});
</script>
</head>
<body>
Testing
</body>
</html>
"""
socketio.run(app, debug=True, log_output=True, use_reloader=False)
I can see the requests the socket is sending in my terminal:
(6548) wsgi starting up on http://127.0.0.1:5000
(6548) accepted ('127.0.0.1', 59354)
127.0.0.1 - - [30/Dec/2020 19:15:58] "GET / HTTP/1.1" 200 691 0.000000
127.0.0.1 - - [30/Dec/2020 19:15:58] "GET /socket.io/?EIO=4&transport=polling&t=NQqtHrO HTTP/1.1" 200 371 0.000997
127.0.0.1 - - [30/Dec/2020 19:15:59] "GET /socket.io/?EIO=4&transport=polling&t=NQqtI28 HTTP/1.1" 200 371 0.000997
127.0.0.1 - - [30/Dec/2020 19:16:00] "GET /socket.io/?EIO=4&transport=polling&t=NQqtILH HTTP/1.1" 200 371 0.000000
127.0.0.1 - - [30/Dec/2020 19:16:03] "GET /socket.io/?EIO=4&transport=polling&t=NQqtJ0u HTTP/1.1" 200 371 0.000996
127.0.0.1 - - [30/Dec/2020 19:16:08] "GET /socket.io/?EIO=4&transport=polling&t=NQqtKFD HTTP/1.1" 200 371 0.001002
127.0.0.1 - - [30/Dec/2020 19:16:13] "GET /socket.io/?EIO=4&transport=polling&t=NQqtLTa HTTP/1.1" 200 371 0.001024

The path option that you are using is not to specify the namespace, it is used to indicate a custom Socket.IO endpoint. Normally you do not need to set the path.
The namespace is given in the connection URL:
var socket1 = io("/test");
Or if you prefer an absolute URL:
var socket1 = io("http://localhost:5000/test");

Related

How to stop infinite api request at backend?

In my dashboard component I am fetching all orders of a user inside useEffect hook. useEffect hook has a dependency of user & orders state.
useEffect(() => {
let isMounted = true;
fetch(`http://localhost:5000/allorders?email=${user?.email}`, {
headers: {
authorization: `Bearer ${localStorage.getItem("accessToken")}`,
},
})
.then((res) => res.json())
.then((data) => {
if (isMounted) {
setOrders(data);
}
})
.catch((error) => console.log(error));
return () => {
isMounted = false;
};
}, [user?.email, orders]);
The problem is I am having infinite api request at /allOrders endpoint of my express server. How can I prevent frontend client from sending infinite request at my backend server?
GET /allorders?email=admin#admin.com 304 - - 59.084 ms
GET /allorders?email=admin#admin.com 304 - - 63.304 ms
GET /allorders?email=admin#admin.com 304 - - 58.676 ms
GET /allorders?email=admin#admin.com 304 - - 57.991 ms
GET /allorders?email=admin#admin.com 304 - - 57.935 ms
GET /allorders?email=admin#admin.com 304 - - 59.366 ms
GET /allorders?email=admin#admin.com 304 - - 61.231 ms
GET /allorders?email=admin#admin.com 304 - - 57.709 ms
GET /allorders?email=admin#admin.com 304 - - 59.637 ms
GET /allorders?email=admin#admin.com 304 - - 69.139 ms
GET /allorders?email=admin#admin.com 304 - - 58.118 ms
GET /allorders?email=admin#admin.com 304 - - 58.127 ms
GET /allorders?email=admin#admin.com 304 - - 61.101 ms
GET /allorders?email=admin#admin.com 304 - - 64.198 ms
I have tried to render the component using useMemo & React.memo(). As I don't have much knowledge of react hooks I encountered multiple error and eventually failed to stop infinite api request.

Axios requests using authentication token sometimes fail in Safari

I'm developing a react (16.9.0) single page app that uses axios (0.19.0). The axios requests use token authentication to access a server running django-rest-framework (3.6.4) and django-cors-headers (3.1.1). The authentication tokens are generated by django-rest-auth (0.9.5) during login.
The app works reliably in Chrome and Firefox. In Safari, some of requests fail due to 401 errors.
This requests succeeds in all three browsers:
INFO basehttp: "GET /apis/games/?slug=pop HTTP/1.1" 200 60932```
the code that generates it looks like:
axios
.get(`${simplUrl}/apis/games/?slug=${gameSlug}`, {
headers: { Authorization: simplToken },
})
.then(res => {
this.setState({
game: res.data[0],
});
...
This request failed with Safari:
INFO basehttp: "OPTIONS /apis/runs/43 HTTP/1.1" 200 0
INFO basehttp: "DELETE /apis/runs/43 HTTP/1.1" 301 0
INFO basehttp: "OPTIONS /apis/runs/43/ HTTP/1.1" 200 0
WARNING basehttp: "DELETE /apis/runs/43/ HTTP/1.1" 401 58
but succeeded with Chrome:
INFO basehttp: "OPTIONS /apis/runs/43 HTTP/1.1" 200 0
INFO basehttp: "DELETE /apis/runs/43 HTTP/1.1" 301 0
INFO basehttp: "OPTIONS /apis/runs/43/ HTTP/1.1" 200 0
INFO basehttp: "DELETE /apis/runs/43/ HTTP/1.1" 204 0
the code that generates it looks like:
const url = `${simplUrl}/apis/runs/${run.id}`;
// console.log('url:', url);
axios
.delete(url, {
headers: { Authorization: simplToken },
})
.then(res => {
// console.log(res);
afterDelete();
});
The Safari 401 response was:
"detail": "Authentication credentials were not provided."
This is the information Safari logged for the failed DELETE request:
The DRF apis views use are based on this mixing:
class CommonViewSet(viewsets.ModelViewSet):
authentication_classes = (TokenAuthentication, BasicAuthentication, SessionAuthentication)
permission_classes = (IsAuthenticated,)
For local development, the DRF server's CORS settings are:
CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_HEADERS = [
'accept',
'accept-encoding',
'authorization',
'content-type',
'dnt',
'origin',
'user-agent',
'x-csrftoken',
'x-requested-with',
]
I don't understand why some requests fail in Safari while others do not. Mostly, I want to insure all requests work in all three browsers.
The solution was to add a trailing slash to urls referencing a single object. The DRF Router docs indicate the correct pattern is:
URL pattern: ^users/{pk}/$ Name: 'user-detail'
Whether it's a bug or a feature that Safari doesn't include the authentication token in redirected requests resulting a 401 error, I'll leave to the reader.
Did you see this ?,I'm not really sure but this discussion may help.
Also, as the error is related to token, try to verify that its sent or added to the request correctly or if it has a type like bearer or somthing.
Also try to log the incoming request headers and its body, so you can make sure that nothing is missing or corrupted.
As this issue happen with DELETE, try to comapre all requests to each other to find out what is missing.

pyopenssl send('GET / HTTP/1.0\r\n\r\n' doesn't returns 'HTTP/1.1 400 Bad Request\

I'm creating a SSL Connection using PyOpenSSL and the trying to make a GET call but i run into :
`'HTTP/1.1 400 Bad Request\r\nDate: Fri, 14 Jul 2017 20:04:51 GMT\r\nServer: Apache/2.4.18 (Ubuntu)\r\nContent-Length: 305\r\nConnection: close\r\nContent-Type: text/html; charset=iso-8859-1\r\n\r\n'
(Pdb) c
.. info: <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>400 Bad Request</title>
</head><body>
<h1>Bad Request</h1>
<p>Your browser sent a request that this server could not understand.<br />
</p>
<hr>
<address>Apache/2.4.18 (Ubuntu) Server at ecdhe-server Port 443</address>
</body></html>`
The Code i have is as follows :
1) I create SSL Connection as follows :
client = socket()
if self._proxy:
client.connect((proxy, 8080))
else:
client.connect((host_name, port))
context = Context(self._ssl_version)
if self._ciphers:
context.set_cipher_list(self._ciphers)
ssl_connection = Connection(context, client)
if self._extension=='SNI':
ssl_connection.set_tlsext_host_name(host_name)
ssl_connection.set_connect_state()
ssl_connection.do_handshake()
self._session_ref = ssl_connection.get_session()
self._ssl_connection = ssl_connection
And then call the get() function which is as follows:
def get(self, http_version='1.0'):
#self._ssl_connection.sendall("GET / HTTP/1.1\r\n\r\n")
self._ssl_connection.sendall("GET / HTTP/1.0\r\n\r\n")
response_contents = self._ssl_connection.recv(4096)
return response_contents
I tried all combinations of sendall and send(also i think) but i run into :
.. info: HTTP/1.1 400 Bad Request
Date: Fri, 14 Jul 2017 20:19:13 GMT
Server: Apache/2.4.18 (Ubuntu)
Content-Length: 305
Connection: close
Content-Type: text/html; charset=iso-8859-1
I would appreciate if some one would help out in resolving the issue.

WebSocket server: sending text frames to client

I'm sending custom web socket frames from server to client. I managed to get handshake seamlessly but sending regular text frames causes me problems (the message on the client side is not received). This is what I send:
unsigned char data2[6] = { 129, 4, 't', 'e', 'x', 't' };
int jj = SDLNet_TCP_Send(client_socket, data2, 6);
The data is sent correctly (handshake worked and jj has value of 6). I based my code on explanation found here How can I send and receive WebSocket messages on the server side?.
My client is quite simple and I'm posting just for completion:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Web Socket Example</title>
<meta charset="UTF-8">
<script type="text/javascript">
var webSocket = new WebSocket("ws://localhost:48884/", "sample");
webSocket.binaryType = "arraybuffer";
webSocket.onopen = function(e) { alert("opened"); }
webSocket.onclose = function(e) { alert("closed"); }
webSocket.onerror = function(e) { alert("error"); }
webSocket.onmessage = function(e) { alert("got: " + e.data); }
</script>
</head>
<body>
<div id="holder" style="width:600px; height:300px"></div>
</body>
</html>
The web socket version I get from client is 13.
Any ideas why handshake worked and regular text doesn't?
I fixed the problem. It works now because it turns out that additional \r\n was necessary at the end of the handshake (https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_servers). So my handshake was not correct but somehow Firefox accepted it (but then didn't accept messages).
Anyhow, the link I posted above says that the handshake format should be:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: key
empty line
I complied to this format and then it all worked fine on Firefox and IE but didn't on Chrome. I found out that to make it work on Chrome I need to also specify the protocol:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: key
Sec-WebSocket-Protocol: my_protocol_name
empty line
The handshake format above got me handshake and server-to-browser message sending working on Firefox, IE and Chrome

Parse response 124, timed out for simple GET request

For the life of me I can't figure this out. I have the following code up on Parse.com:
Parse.Cloud.httpRequest({
method: "GET",
url: 'http://www.csse.monash.edu.au/~jwb/cgi-bin/wwwjdic.cgi?9ZIG%EF%BC%B0%EF%BC%B2%EF%BC',
success: function(httpResponse) {
response.success(httpResponse.text);
},
error: function(httpResponse) {
response.error('Request failed with response ' + httpResponse.status);
}
});
It's a simple GET request, but it hangs and after about 10 seconds, Parse.com will time out with error 124: Request Timed Out.
If I substitute https://www.google.com or https://parse.com, it will deliver me the results instantaneously. So, I thought it might be the page I'm trying to load, but I can access http://www.csse.monash.edu.au/~jwb/cgi-bin/wwwjdic.cgi?9ZIG%EF%BC%B0%EF%BC%B2%EF%BC on my browser and it loads pretty much instantaneously.
The request also loads pretty much instantaneously when I use cURL:
curl -v http://www.csse.monash.edu.au/~jwb/cgi-bin/wwwjdic.cgi?9ZIG%EF%BC%B0%EF%BC%B2%EF%BC
* Adding handle: conn: 0x7fcb0c800000
* Adding handle: send: 0
* Adding handle: recv: 0
* Curl_addHandleToPipeline: length: 1
* - Conn 0 (0x7fcb0c800000) send_pipe: 1, recv_pipe: 0
* About to connect() to www.csse.monash.edu.au port 80 (#0)
* Trying 130.194.64.145...
* Connected to www.csse.monash.edu.au (130.194.64.145) port 80 (#0)
> GET /~jwb/cgi-bin/wwwjdic.cgi?9ZIG%EF%BC%B0%EF%BC%B2%EF%BC HTTP/1.1
> User-Agent: curl/7.30.0
> Host: www.csse.monash.edu.au
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Sun, 21 Sep 2014 02:30:23 GMT
* Server Apache/1.3.26 (Unix) mod_layout/3.0.4 mod_ssl/2.8.10 OpenSSL/0.9.6e is not blacklisted
< Server: Apache/1.3.26 (Unix) mod_layout/3.0.4 mod_ssl/2.8.10 OpenSSL/0.9.6e
< Transfer-Encoding: chunked
< Content-Type: text/html; charset=UTF-8
<
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<HTML>
<HEAD><META http-equiv="Content-Type" content="text/html; charset=UTF-8"><TITLE>WWWJDIC: Text/word translation display</TITLE>
</HEAD><BODY>
<br>
<FONT color="red">PR</FONT>。<br>
<ul><li> PR 【ピーアール】 (n) (See パブリックリレーションズ) public relations; PR; ED </li>
</ul><br>
</BODY>
</HTML>
* Connection #0 to host www.csse.monash.edu.au left intact
I feel like I must be missing something really simple. I added all the headers and none seemed to make a difference. Does anyone have an idea?
OK I've worked this out and it's taken me HOURS. Firstly Parse will not accept httpRequests outside of Cloud Code beforeSave, afterSave and cloud functions. You will also have to use a Parse Promise.
So in main.js in your Cloud Code setup create the function testParse like this:
Parse.Cloud.define("testParse", function(request, response) {
var promises = [];
promises.push(Parse.Cloud.httpRequest({
method: "GET",
url: 'http://www.csse.monash.edu.au/~jwb/cgi-bin/wwwjdic.cgi?9ZIG%EF%BC%B0%EF%BC%B2%EF%BC'
});
Parse.Promise.when(promises).then(function(results) {
response.success(results.status);
}, function(error) {
response.error(error);
});
});
To call the function you will use
Parse.Cloud.run('testParse');
This solution works. Frustrating though, only 10% of the time. I still get timeouts.
Edit:
OK got it to work. On the Parse.Cloud.define error response call the function again:
Parse.Promise.when(promises).then(function(results) {
response.success(results.status);
}, function(error) {
Parse.Cloud.run('testParse');
});

Resources