Check a handshake request and negotiate extensions and subprotocol. This function doesn't verify that the request is an HTTP/1.1 or higher GET request and doesn't check the ``Host`` header. These controls are usually performed earlier in the HTTP request handling co
(
self,
request: Request,
)
| 203 | return Response(101, "Switching Protocols", headers) |
| 204 | |
| 205 | def process_request( |
| 206 | self, |
| 207 | request: Request, |
| 208 | ) -> tuple[str, str | None, str | None]: |
| 209 | """ |
| 210 | Check a handshake request and negotiate extensions and subprotocol. |
| 211 | |
| 212 | This function doesn't verify that the request is an HTTP/1.1 or higher |
| 213 | GET request and doesn't check the ``Host`` header. These controls are |
| 214 | usually performed earlier in the HTTP request handling code. They're |
| 215 | the responsibility of the caller. |
| 216 | |
| 217 | Args: |
| 218 | request: WebSocket handshake request received from the client. |
| 219 | |
| 220 | Returns: |
| 221 | ``Sec-WebSocket-Accept``, ``Sec-WebSocket-Extensions``, and |
| 222 | ``Sec-WebSocket-Protocol`` headers for the handshake response. |
| 223 | |
| 224 | Raises: |
| 225 | InvalidHandshake: If the handshake request is invalid; |
| 226 | then the server must return 400 Bad Request error. |
| 227 | |
| 228 | """ |
| 229 | headers = request.headers |
| 230 | |
| 231 | connection: list[ConnectionOption] = sum( |
| 232 | [parse_connection(value) for value in headers.get_all("Connection")], [] |
| 233 | ) |
| 234 | if not any(value.lower() == "upgrade" for value in connection): |
| 235 | raise InvalidUpgrade( |
| 236 | "Connection", ", ".join(connection) if connection else None |
| 237 | ) |
| 238 | |
| 239 | upgrade: list[UpgradeProtocol] = sum( |
| 240 | [parse_upgrade(value) for value in headers.get_all("Upgrade")], [] |
| 241 | ) |
| 242 | # For compatibility with non-strict implementations, ignore case when |
| 243 | # checking the Upgrade header. The RFC always uses "websocket", except |
| 244 | # in section 11.2. (IANA registration) where it uses "WebSocket". |
| 245 | if not (len(upgrade) == 1 and upgrade[0].lower() == "websocket"): |
| 246 | raise InvalidUpgrade("Upgrade", ", ".join(upgrade) if upgrade else None) |
| 247 | |
| 248 | try: |
| 249 | key = headers["Sec-WebSocket-Key"] |
| 250 | except KeyError: |
| 251 | raise InvalidHeader("Sec-WebSocket-Key") from None |
| 252 | except MultipleValuesError: |
| 253 | raise InvalidHeader("Sec-WebSocket-Key", "multiple values") from None |
| 254 | try: |
| 255 | raw_key = base64.b64decode(key.encode(), validate=True) |
| 256 | except binascii.Error as exc: |
| 257 | raise InvalidHeaderValue("Sec-WebSocket-Key", key) from exc |
| 258 | if len(raw_key) != 16: |
| 259 | raise InvalidHeaderValue("Sec-WebSocket-Key", key) |
| 260 | accept_header = accept_key(key) |
| 261 | |
| 262 | try: |
no test coverage detected