def handle_group_exclude(self, req, connection): data = json.loads(req.body) if not data["users"]: raise HTTPError(400, "Bad Request") token = data["auth_token"] admin = self._tokens_conn[token].login chat_name = data["name"] users = set(data["users"]) users = users.intersection(set(self._users.keys())) if not self._chat_groups.exists(chat_name): raise HTTPError(404, 'Not found') if admin != self._chat_groups[chat_name].admin: raise HTTPError(401, "Unauthorized") all_users = self._chat_groups[chat_name].users.copy() self._chat_groups.remove_users(chat_name, users) inform = handle_response(req=req, resp_body={"status": "users excluded", "name": chat_name, "users": list(users)}, resp_status=200, resp_reason="OK", encoding="utf-8") for user in users: self._users[user].chats.discard(chat_name) self.broadcast(inform, all_users, connection) return handle_response(req=req, resp_body={"status": "excluded", "name": chat_name, "users": list(users)}, resp_status=200, resp_reason="OK", encoding="utf-8")
def handle_message(self, req: Request, connection: socket.socket) -> Response: recievers_group = req.path[len('/message/'):] data = json.loads(req.body) fl = True auth_token = data["auth_token"] if self._tokens_conn[auth_token] is None: raise HTTPError(404, 'Not found') if not self._chat_groups.exists(recievers_group): raise HTTPError(404, 'Not found') if self._chat_groups[recievers_group].has_user( self._tokens_conn[auth_token].login): data["text"] = ( self._tokens_conn[auth_token].login) + ": " + data["text"] fl = False self.send_message(req, recievers_group, data, connection) else: raise HTTPError(401, "Unauthorized") if fl: data["text"] = ( self._tokens_conn[auth_token].login) + ": " + data["text"] return handle_response(req=req, resp_body={ "status": "sent", "text": data["text"], "group": recievers_group }, resp_status=200, resp_reason='OK', encoding='utf-8')
def handle_group_delete(self, req, connection): data = json.loads(req.body) token = data["auth_token"] admin = self._tokens_conn[token].login chat_name = data["name"] if not self._chat_groups.exists(chat_name): raise HTTPError(404, 'Not found') if admin != self._chat_groups[chat_name].admin: raise HTTPError(401, "Unauthorized") users = self._chat_groups[chat_name].users.copy() del self._chat_groups[chat_name] for user in users: self._users[user].chats.discard(chat_name) inform = handle_response(req=req, resp_body={ "status": "group deleted", "name": chat_name }, resp_status=200, resp_reason="OK", encoding="utf-8") self.broadcast(inform, users, connection) return handle_response(req=req, resp_body={ "status": "delete group", "name": chat_name }, resp_status=200, resp_reason="OK", encoding="utf-8")
def handle_group_create(self, req, connection): data = json.loads(req.body) if not data["users"]: raise HTTPError(400, "Bad Request") token = data["auth_token"] admin = self._tokens_conn[token].login if not self._chat_groups.exists(data["name"]): users = set(data["users"]).intersection(set(self._users.keys())) self._chat_groups[data["name"]] = ChatGroup( data["name"], admin, users) self._users[admin].chats.add(data["name"]) for user in users: self._users[user].chats.add(data["name"]) inform = handle_response(req=req, resp_body={ "status": "added to group", "name": data["name"] }, resp_status=200, resp_reason="OK", encoding="utf-8") self.broadcast(inform, users, connection) return handle_response(req=req, resp_body={ "status": "create group", "name": data["name"] }, resp_status=204, resp_reason="Created", encoding="utf-8") raise HTTPError(401, "Unauthorized")
def parse_request(self, conn): rfile = conn.makefile('rb') method, target, ver = self.parse_request_line(rfile) headers = self.parse_headers(rfile) host = headers.get('Host') if not host: raise HTTPError(400, 'Bad request', 'Host header is missing') if host not in (self._server_name, f'{self._server_name}:{self._port}'): raise HTTPError(404, 'Not found') return Request(method, target, ver, headers, rfile)
def handle_post_login(self, req, connection: socket.socket): data = json.loads(req.body) login, password = data["login"], data["password"] if self._users[login] is None: raise HTTPError(404, 'Not found') if self._users[login].password != password: raise HTTPError(404, "Unauthorized - wrong password") auth_token = self._users.token_for_user(login=login, tokens_conn=self._tokens_conn, conn_pool=self._pool, conn=connection) logging.info(self._users[login].chats) return handle_response(req=req, resp_body={"status": "logged in", "token": auth_token, "chats": list(self._users[login].chats)}, resp_status=200, resp_reason='OK', encoding='utf-8', keep_alive=True)
def parse_request_line(self, rfile): raw = rfile.readline(MAX_LINE + 1) if len(raw) > MAX_LINE: raise HTTPError(400, 'Bad request', 'Request line is too long') req_line = str(raw, 'iso-8859-1') words = req_line.split() if len(words) != 3: raise HTTPError(400, 'Bad request', 'Malformed request line') method, target, ver = words if ver != 'HTTP/1.1': raise HTTPError(505, 'HTTP Version Not Supported') return method, target, ver
def handle_request(self, req: Request, connection: socket.socket) -> Response: if req.path == '/disconnect' and req.method == 'POST': self.handle_post_disconnect(req, connection) if req.path == '/registry' and req.method == 'POST': return self.handle_post_registry(req) if req.path == '/remove' and req.method == 'POST': return self.handle_post_remove(req) if req.path == '/login' and req.method == 'POST': return self.handle_post_login(req, connection) if req.path == '/logout' and req.method == 'POST': self._connections[connection] = ConnStatus.closing return self.handle_post_logout(req) if req.path == '/users' and req.method == 'GET': return self.handle_get_users(req) if req.path == '/test' and req.method == 'GET': return self.handle_inf_test(req) if req.path.startswith('/message/') and req.method == 'POST': return self.handle_message(req, connection) if req.path.startswith('/group/') and req.method == 'POST': return self.handle_group_action(req, connection) if req.path.startswith('/users/'): user_id = req.path[len('/users/'):] if user_id.isdigit(): return self.handle_get_user(req, user_id) raise HTTPError(404, 'Not found')
def parse_headers(self, rfile): headers = [] while True: line = rfile.readline(MAX_LINE + 1) if len(line) > MAX_LINE: raise HTTPError(494, 'Request header too large') if line in (b'\r\n', b'\n', b''): break headers.append(line) if len(headers) > MAX_HEADERS: raise HTTPError(494, 'Too many headers') sheaders = b''.join(headers).decode('iso-8859-1') return Parser().parsestr(sheaders)
def handle_group_action(self, req, connection): data = json.loads(req.body) action = req.path[len('/group/'):] if not data["auth_token"]: raise HTTPError(401, "Unauthorized") if not data["name"]: raise HTTPError(400, "Bad Request") if action == "create": return self.handle_group_create(req, connection) elif action == "delete": return self.handle_group_delete(req, connection) elif action == "add": return self.handle_group_add(req, connection) elif action == "exclude": return self.handle_group_exclude(req, connection) raise HTTPError(404, 'Not found')
def handle_prepare(self, req: Request): accept = req.headers.get('Accept') data = json.loads(req.body) auth_token = data["auth_token"] if self._tokens_conn.get(auth_token): return accept, data, auth_token else: raise HTTPError(400, "Invalid token")
def handle_get_user(self, req: Request, login: str) -> Response: user = self._users[login] if not user: raise HTTPError(404, 'Not found') return handle_response(req=req, resp_body=user.json_prepare(), resp_status=200, resp_reason='OK', encoding='utf-8')
def handle_response(req: Request, resp_body, resp_status, resp_reason, encoding: str, default=None, keep_alive=False) -> Response: accept = req.headers.get('Accept') if 'application/json' in accept: contentType = f'application/json; charset={encoding}' body = json.dumps(resp_body, default=default) else: # https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/406 raise HTTPError(406, 'Not Acceptable') body = body.encode(f'{encoding}') headers = [('Content-Type', contentType), ('Content-Length', len(body))] if keep_alive: headers.append(('Connection', 'Keep-Alive')) headers.append(('Keep-Alive', 'timeout=5, max=1000')) return Response(resp_status, resp_reason, headers, body)