Python Server Websocket Handshake Response - javascript

I was wondering how to respond to a javascript websocket handshake in Python 3, I can't seem to figure out how I should respond on the server side of things. I got this request from my client webpage:
GET / HTTP/1.1
Host: localhost:8080
Connection: Upgrade
Pragma: no-cache
Cache-Control: no-cache
Upgrade: websocket
Origin: http://www.w3schools.com
Sec-WebSocket-Version: 13
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.81 Safari/537.36
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8
Sec-WebSocket-Key: euv7CmNNT22p59HbD3X7ww==
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
I can tell that I proably won't care about most of this, I just need to know what HTTP headers and such to send so that I can set this websocket up. Thanks!

Converted from Python2 code here: https://gist.github.com/jkp/3136208
Here is the server side Python3 code to verify client browser & return it an handshake confirmation:
MAGIC = b'258EAFA5-E914-47DA-95CA-C5AB0DC85B11' # Fix key for handshake on server side
class WebSocketsHandler(socketserver.StreamRequestHandler):
def handshake(self):
data = self.request.recv(1024).strip()
hsKey = hsUpgrade = b''
for header in data.split(b'\r\n'):
if header.startswith(b'Sec-WebSocket-Key'): hsKey = header.split(b':')[1].strip()
if header.startswith(b'Upgrade'): hsUpgrade = header.split(b':')[1].strip()
if hsUpgrade != b"websocket": return
digest = b64encode(bytes.fromhex(sha1(hsKey + MAGIC).hexdigest())).decode('utf-8')
response = ('HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\n'
'Connection: Upgrade\r\nSec-WebSocket-Accept: {}\r\n\r\n'.format(digest))
print('Handshaking...{}'.format(digest))
self.handshake_done = self.request.send(response.encode('utf8'))

Related

HTTP protocol version undefined in requests to my socket.io server?

I have a socket.io server setup on an AWS EC2 instance. I am able to connect fine, as are most people, but I'm running into an issue with a couple of users where the HTTP protocol version is undefined. I have supplied two requests to my socket io server, one with an expected HTTP version, and one where it is undefined. It seems that otherwise the requests are the same, which leads me to believe that the HTTP version is the problem.
GET Request that is working fine (removed specific ip/website info)
GET /socket.io/?EIO=3&transport=polling&t=Nit_A4F HTTP/1.1
Host: {{My EC2 Host:Port}}
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:91.0) Gecko/20100101 Firefox/91.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Origin: {{My Website}}
Connection: keep-alive
Referer: {{My Website}}
GET Request that is failing (Note line 1, where the HTTP version is undefined, rather than HTTP/1.1)
GET /socket.io/?EIO=3&transport=polling&t=Nit_UGj undefined
Host: {{My EC2 Host:Port}}
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:90.0) Gecko/20100101 Firefox/90.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Origin: {{My Website}}
Connection: keep-alive
Referer: {{My Website}}
Pragma: no-cache
Cache-Control: no-cache
There's a couple of questions in this problem, really. First, is the undefined HTTP protocol version a common or reasonable use case? If so, is there a way I can manually set the HTTP protocol version on the frontend (Angular), or set up CORS to handle the undefined HTTP protocol version on the backend?
If the undefined HTTP protocol version is not a reasonable use case, is there anything these users can do to fix it?
Here is my current socket.io setup on the backend with CORS:
const io = require('socket.io')(server, {
cors: {
origin: '*',
methods: ['GET', 'POST'],
transports: [ 'websocket', 'polling' ],
credentials: true,
}
});
I don't have much on my frontend besides just connecting to the correct url, but here it is just in case:
export class SocketIOService {
private socket: io.Socket;
constructor() {
this.socket = io(
environment.socketUrl
);
}
sendData(socketEvent: string, data: any) {
this.socket.emit(socketEvent, data);
}
getData(socketEvent: string) {
return new Observable(observer => {
this.socket.on(socketEvent, msg => {
console.log("handling event");
observer.next(msg);
});
});
}
}
Any help here would be appreciated.
For anyone looking for an answer as to why this specific problem occurs, I can't say I have an answer.
The solution that was applicable to me to solve my issue was to upgrade my frontend and backend to communicate through https instead of http.

Using http request headers to enforce caching of response

I'm working with a public API that is poorly configured, i.e. the server doesn't set the Cache-Control header when it should.
Can I use HTTP request headers or alter response headers, so that a response is cached at the browser level for some period of time?
In the context of this API the response will be fresh until a specific data time calculated previously.
I looked quite a bit, but cannot seem to find anything related to setting request headers.
Note, I'm working in javascript and using fetch() to make requests.
Here is the state of the current headers:
Request Headers
:authority: fantasy.premierleague.com
:method: GET
:path: /api/entry/1157414/event/3/picks/
:scheme: https
accept: */*
accept-encoding: gzip, deflate, br
accept-language: en-GB,en-US;q=0.9,en;q=0.8
sec-ch-ua: "Google Chrome";v="87", " Not;A Brand";v="99", "Chromium";v="87"
sec-ch-ua-mobile: ?0
sec-fetch-dest: empty
sec-fetch-mode: cors
sec-fetch-site: same-origin
user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
Response Headers
accept-ranges: bytes
content-length: 571
content-type: text/html
date: Fri, 25 Dec 2020 16:57:32 GMT
server: nginx/1.18.0
via: 1.1 google, 1.1 varnish, 1.1 varnish
x-cache: MISS, MISS
x-cache-hits: 0, 0
x-served-by: cache-lhr7366-LHR, cache-fra19130-FRA
x-timer: S1608915452.118518,VS0,VE22

deploy angular in aws Elastic Beanstalk 502 stauts code

Cannot deploy my angular 7 project in AWS Elastic Beanstalk, but I could deploy my express project, any idea?
This is the Request.
Request URL: http://mingzhi-event-search.us-east-2.elasticbeanstalk.com/favicon.ico
Request Method: GET
Status Code: 502 Bad Gateway
Remote Address: 18.223.167.56:80
Referrer Policy: no-referrer-when-downgrade
Connection: keep-alive
Content-Length: 575
Content-Type: text/html
Date: Fri, 16 Nov 2018 10:39:03 GMT
Server: nginx/1.12.1
Accept: image/webp,image/apng,image/*,*/*;q=0.8
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,zh-TW;q=0.8,en;q=0.7
Cache-Control: no-cache
Connection: keep-alive
Host: mingzhi-event-search.us-east-2.elasticbeanstalk.com
Pragma: no-cache
Referer: http://mingzhi-event-search.us-east-2.elasticbeanstalk.com/
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36
Angular is a front-end engine, not a server. If you wanna deploy an Angular application on AWS without a server, you should store the application in a Bucket and properly set the permissions.
Otherwise, you have to set up a server (e.g. a NodeJS application, but whatever) and deploy it using Elastic BeanStalk.

Websockets sending garbage to server

I have created a WebSockets connection from my website to my home server running a python script listening on port 3000. I can connect to the server just fine as the server logs that a client has connected when I load my page. However each time I connect to the server, the server automatically fires my servers receivedMessage() function and prints out a bunch of garbage regarding the connection. The servers logs are below:
A new client has connected
Message Received: GET / HTTP/1.1
Host: [Insert host name and port here]
Connection: Upgrade
Pragma: no-cache
Cache-Control: no-cache
Upgrade: websocket
Origin: null
Sec-WebSocket-Version: 13
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8
Sec-WebSocket-Key: 3DUmKD70X9p19IpLPjS2jg==
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
The snippet of code to connect to the server is simple enough:
var theSocket = new WebSocket("ws://[insert host name]:3000");
theSocket.onopen = function() {
// Web Socket is connected, send data using send()
theSocket.send("blah");
alert("SENT");
};
Also the alert box never shows up when the above script is run. What is causing all the connection details to print and how do I get it to send a simple string and successfully pop up the alert box?
Its likely that your WebSocket is never transitioning from CONNECTING to OPEN and thus never calling your onopen function. You need to make sure your python script is going through the Web Socket Handshake on the server side.

CORS Ajax post with Jetty/Firefox

I'm trying to do a cross-domain POST with jQuery using CORS, but after the OPTIONS request is sent (and responded to), the POST doesn't happen. My request/response filters are shown below. My jQuery post code is also shown. It looks like the response has the proper CORS response headers, so I'm not sure why this isn't working.
var params = {};
params.data = myPostData;
params.headers = {
'x-pingother' : 'pingpong'
};
$.ajax(params);
Request Header
OPTIONS /my/service/url HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:17.0) Gecko/20100101 Firefox/17.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Origin: http://localhost:9876
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type,x-pingother
Pragma: no-cache
Cache-Control: no-cache
Response Header:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://localhost:9876
Access-Control-Allow-Methods: POST,GET,OPTIONS
Access-Control-Allow-Headers: x-pingother
Content-Length: 703
Content-Type: application/vnd.sun.wadl+xml
Allow: OPTIONS,POST
Last-Modified: Sat, 19 Jan 2013 13:46:51 EST
Server: Jetty(6.1.25)
I'm running automated tests from a local server (JSTestDriver) that connects to a web server running on a different port. The web server runs on 8080 and the page making the request runs on 9876.
This was solved by adding the response headers as specified in
jQuery CORS request not working when sending Range request
Did you try to explicitly tell jQuery to enable cors?
$.support.cors = true;

Categories

Resources