Pithikos / python-websocket-server

A simple fully working websocket-server in Python with no external dependencies

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

KeyError: 'upgrade'

Darth-Carrotpie opened this issue · comments

Sometimes getting a weird error. Not sure on what action exactly...

2018-08-24 10:13:03,075 DEBUG webserver client left: None

Exception happened during processing of request from ('122.228.10.51', 26823)
Traceback (most recent call last):
File "/usr/lib64/python3.6/socketserver.py", line 639, in process_request_thread
self.finish_request(request, client_address)
File "/usr/lib64/python3.6/socketserver.py", line 361, in finish_request
self.RequestHandlerClass(request, client_address, self)
File "/home/ec2-user/libraries/websocket_server.py", line 166, in init
StreamRequestHandler.init(self, socket, addr, server)
File "/usr/lib64/python3.6/socketserver.py", line 696, in init
self.handle()
File "/home/ec2-user/libraries/websocket_server.py", line 177, in handle
self.handshake()
File "/home/ec2-user/libraries/websocket_server.py", line 319, in handshake
assert headers['upgrade'].lower() == 'websocket'
KeyError: 'upgrade'

I have the same issue. I'm currently trying to interconnect a python process (implementing python-websocket-server) and a nodejs server (on the same machine) with socket.io client.

This error disappeared by changing the options passed to the socket.io client instanciation like so

var ioClient = require('socket.io-client');

var myClient = ioClient('http://127.0.0.1:1234', {
  "upgrade": true,
  "transports": ['websocket']
});

it's still do not work because the connection is closed right away..

Well, I think I figured out what's causing the errors for me.
Since my server is being hosted in Amazon AWS, there could be all kinds of crawlers checking for services and such. I think the server loses its mind, when there's a http message, which looks similar to:
b'\x03\x00\x00/*\xe0\x00\x00\x00\x00\x00Cookie: mstshash=Administr\r\n'
Whenever these messages occur, server breaks.

I ran into this same error when I was attempting to use SSL. If I run a server without it, then everything works just fine. As soon as I add an SSL cert into the mix, I first get an error:

Traceback (most recent call last):
  File "/usr/lib/python3.6/socketserver.py", line 721, in __init__
    self.handle()
  File "/home/damian/hopemud/websocket_server/websocket_server.py", line 199, in handle
    self.handshake()
  File "/home/damian/hopemud/websocket_server/websocket_server.py", line 334, in handshake
    headers = self.read_http_headers()
  File "/home/damian/hopemud/websocket_server/websocket_server.py", line 322, in read_http_headers
    http_get = self.rfile.readline().decode().strip()
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xfc in position 8: invalid start byte

Then, when I add a a proxy_pass to try to upgrade the header for the web client, I get the same error you do:

Traceback (most recent call last):
  File "/usr/lib/python3.6/socketserver.py", line 721, in __init__
    self.handle()
  File "/home/damian/hopemud/websocket_server/websocket_server.py", line 199, in handle
    self.handshake()
  File "/home/damian/hopemud/websocket_server/websocket_server.py", line 337, in handshake
    assert headers['upgrade'].lower() == 'websocket'
KeyError: 'upgrade'

Have not found a way around this.

Same problem here. :(
Has anybody found a solution, yet?

    def handshake(self):
        headers = self.read_http_headers()
        print("Handshake", headers)
        if 'upgrade' in headers:
            
            try:
                assert headers['upgrade'].lower() == 'websocket'
            except AssertionError:
                self.keep_alive = False
                return

            try:
                key = headers['sec-websocket-key']
            except KeyError:
                logger.warning("Client tried to connect but was missing a key")
                self.keep_alive = False
                return

            response = self.make_handshake_response(key)
            with self._send_lock:
                self.handshake_done = self.request.send(response.encode())
            self.valid_client = True
            self.server._new_client_(self)
        else:
            print("请升级到ws协议")

修改库文件代码

    def read_http_headers(self):
        headers = {}
        # first line should be HTTP GET
        http_get = self.rfile.readline().decode().strip()
        
        if not http_get.upper().startswith('GET'):
            logger.warning("Unsupported HTTP method")
            response = 'HTTP/1.1 400 Bad Request\r\n\r\n'
            with self._send_lock:
                self.request.sendall(response.encode())
            self.keep_alive = False
            return headers           
                 
        
        #assert http_get.upper().startswith('GET')
        # remaining should be headers
        while True:
            header = self.rfile.readline().decode().strip()
            if not header:
                break
            head, value = header.split(':', 1)
            headers[head.lower().strip()] = value.strip()
        return headers

    def handshake(self):
        headers = self.read_http_headers()
        #print("Handshake", headers)
        #针对
        if 'upgrade' in headers:
            
            try:
                assert headers['upgrade'].lower() == 'websocket'
            except AssertionError:
                self.keep_alive = False
                return

            try:
                key = headers['sec-websocket-key']
            except KeyError:
                logger.warning("Client tried to connect but was missing a key")
                self.keep_alive = False
                return

            response = self.make_handshake_response(key)
            with self._send_lock:
                self.handshake_done = self.request.send(response.encode())
            self.valid_client = True
            self.server._new_client_(self)
        else:
            timeStr = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
            print(f"请升级到ws协议{timeStr}")
            response = 'HTTP/1.1 400 Bad Request\r\n\r\n'
            #如果客户端不支持WebSocket协议,服务器会返回一个HTTP 401 Unauthorized状态码,表示客户端没有权限访问该资源。
            with self._send_lock:
                self.request.sendall(response.encode())
            self.keep_alive = False