prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Denying WebSocket connection in WebSocketEndpoint.on_connect leads to Exception
  ### Discussed in https://github.com/encode/starlette/discussions/1555
  
  <div type='discussions-op-text'>
  
  <sup>Originally posted by **dingensundso** March 27, 2022</sup>
  I created a WebSocketEndpoint class in which I want to deny the connection in certain conditions.
  When the WebSocket is closed in on_connect I receive the following exception:
  
  ```
    File "starlette/endpoints.py", line 83, in dispatch
      close_code = int(message.get("code", status.WS_1000_NORMAL_CLOSURE))
  TypeError: int() argument must be a string, a bytes-like object or a real number, not 'NoneType'
  ```
  So code is None when the server denies the connection instead of non-existant.
  
  https://github.com/encode/starlette/blob/e086fc2da361767b532cf690e5203619bbae98aa/starlette/endpoints.py#L72-L87
  
  Changing line 83 to the following should fix the issue:
  ```python
  close_code = int(message.get("code") or status.WS_1000_NORMAL_CLOSURE)               
  ````
  </div>
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `starlette/endpoints.py`
  Content:
  ```
  1 import asyncio
  2 import json
  3 import typing
  4 
  5 from starlette import status
  6 from starlette.concurrency import run_in_threadpool
  7 from starlette.exceptions import HTTPException
  8 from starlette.requests import Request
  9 from starlette.responses import PlainTextResponse, Response
  10 from starlette.types import Message, Receive, Scope, Send
  11 from starlette.websockets import WebSocket
  12 
  13 
  14 class HTTPEndpoint:
  15     def __init__(self, scope: Scope, receive: Receive, send: Send) -> None:
  16         assert scope["type"] == "http"
  17         self.scope = scope
  18         self.receive = receive
  19         self.send = send
  20         self._allowed_methods = [
  21             method
  22             for method in ("GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "OPTIONS")
  23             if getattr(self, method.lower(), None) is not None
  24         ]
  25 
  26     def __await__(self) -> typing.Generator:
  27         return self.dispatch().__await__()
  28 
  29     async def dispatch(self) -> None:
  30         request = Request(self.scope, receive=self.receive)
  31         handler_name = (
  32             "get"
  33             if request.method == "HEAD" and not hasattr(self, "head")
  34             else request.method.lower()
  35         )
  36 
  37         handler: typing.Callable[[Request], typing.Any] = getattr(
  38             self, handler_name, self.method_not_allowed
  39         )
  40         is_async = asyncio.iscoroutinefunction(handler)
  41         if is_async:
  42             response = await handler(request)
  43         else:
  44             response = await run_in_threadpool(handler, request)
  45         await response(self.scope, self.receive, self.send)
  46 
  47     async def method_not_allowed(self, request: Request) -> Response:
  48         # If we're running inside a starlette application then raise an
  49         # exception, so that the configurable exception handler can deal with
  50         # returning the response. For plain ASGI apps, just return the response.
  51         headers = {"Allow": ", ".join(self._allowed_methods)}
  52         if "app" in self.scope:
  53             raise HTTPException(status_code=405, headers=headers)
  54         return PlainTextResponse("Method Not Allowed", status_code=405, headers=headers)
  55 
  56 
  57 class WebSocketEndpoint:
  58 
  59     encoding: typing.Optional[str] = None  # May be "text", "bytes", or "json".
  60 
  61     def __init__(self, scope: Scope, receive: Receive, send: Send) -> None:
  62         assert scope["type"] == "websocket"
  63         self.scope = scope
  64         self.receive = receive
  65         self.send = send
  66 
  67     def __await__(self) -> typing.Generator:
  68         return self.dispatch().__await__()
  69 
  70     async def dispatch(self) -> None:
  71         websocket = WebSocket(self.scope, receive=self.receive, send=self.send)
  72         await self.on_connect(websocket)
  73 
  74         close_code = status.WS_1000_NORMAL_CLOSURE
  75 
  76         try:
  77             while True:
  78                 message = await websocket.receive()
  79                 if message["type"] == "websocket.receive":
  80                     data = await self.decode(websocket, message)
  81                     await self.on_receive(websocket, data)
  82                 elif message["type"] == "websocket.disconnect":
  83                     close_code = int(message.get("code", status.WS_1000_NORMAL_CLOSURE))
  84                     break
  85         except Exception as exc:
  86             close_code = status.WS_1011_INTERNAL_ERROR
  87             raise exc
  88         finally:
  89             await self.on_disconnect(websocket, close_code)
  90 
  91     async def decode(self, websocket: WebSocket, message: Message) -> typing.Any:
  92 
  93         if self.encoding == "text":
  94             if "text" not in message:
  95                 await websocket.close(code=status.WS_1003_UNSUPPORTED_DATA)
  96                 raise RuntimeError("Expected text websocket messages, but got bytes")
  97             return message["text"]
  98 
  99         elif self.encoding == "bytes":
  100             if "bytes" not in message:
  101                 await websocket.close(code=status.WS_1003_UNSUPPORTED_DATA)
  102                 raise RuntimeError("Expected bytes websocket messages, but got text")
  103             return message["bytes"]
  104 
  105         elif self.encoding == "json":
  106             if message.get("text") is not None:
  107                 text = message["text"]
  108             else:
  109                 text = message["bytes"].decode("utf-8")
  110 
  111             try:
  112                 return json.loads(text)
  113             except json.decoder.JSONDecodeError:
  114                 await websocket.close(code=status.WS_1003_UNSUPPORTED_DATA)
  115                 raise RuntimeError("Malformed JSON data received.")
  116 
  117         assert (
  118             self.encoding is None
  119         ), f"Unsupported 'encoding' attribute {self.encoding}"
  120         return message["text"] if message.get("text") else message["bytes"]
  121 
  122     async def on_connect(self, websocket: WebSocket) -> None:
  123         """Override to handle an incoming websocket connection"""
  124         await websocket.accept()
  125 
  126     async def on_receive(self, websocket: WebSocket, data: typing.Any) -> None:
  127         """Override to handle an incoming websocket message"""
  128 
  129     async def on_disconnect(self, websocket: WebSocket, close_code: int) -> None:
  130         """Override to handle a disconnecting websocket"""
  131
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/starlette/endpoints.py b/starlette/endpoints.py
  --- a/starlette/endpoints.py
  +++ b/starlette/endpoints.py
  @@ -80,7 +80,9 @@
                       data = await self.decode(websocket, message)
                       await self.on_receive(websocket, data)
                   elif message["type"] == "websocket.disconnect":
  -                    close_code = int(message.get("code", status.WS_1000_NORMAL_CLOSURE))
  +                    close_code = int(
  +                        message.get("code") or status.WS_1000_NORMAL_CLOSURE
  +                    )
                       break
           except Exception as exc:
               close_code = status.WS_1011_INTERNAL_ERROR
  
verification_info: {"golden_diff": "diff --git a/starlette/endpoints.py b/starlette/endpoints.py\n--- a/starlette/endpoints.py\n+++ b/starlette/endpoints.py\n@@ -80,7 +80,9 @@\n                     data = await self.decode(websocket, message)\n                     await self.on_receive(websocket, data)\n                 elif message[\"type\"] == \"websocket.disconnect\":\n-                    close_code = int(message.get(\"code\", status.WS_1000_NORMAL_CLOSURE))\n+                    close_code = int(\n+                        message.get(\"code\") or status.WS_1000_NORMAL_CLOSURE\n+                    )\n                     break\n         except Exception as exc:\n             close_code = status.WS_1011_INTERNAL_ERROR\n", "issue": "Denying WebSocket connection in WebSocketEndpoint.on_connect leads to Exception\n### Discussed in https://github.com/encode/starlette/discussions/1555\r\n\r\n<div type='discussions-op-text'>\r\n\r\n<sup>Originally posted by **dingensundso** March 27, 2022</sup>\r\nI created a WebSocketEndpoint class in which I want to deny the connection in certain conditions.\r\nWhen the WebSocket is closed in on_connect I receive the following exception:\r\n\r\n```\r\n  File \"starlette/endpoints.py\", line 83, in dispatch\r\n    close_code = int(message.get(\"code\", status.WS_1000_NORMAL_CLOSURE))\r\nTypeError: int() argument must be a string, a bytes-like object or a real number, not 'NoneType'\r\n```\r\nSo code is None when the server denies the connection instead of non-existant.\r\n\r\nhttps://github.com/encode/starlette/blob/e086fc2da361767b532cf690e5203619bbae98aa/starlette/endpoints.py#L72-L87\r\n\r\nChanging line 83 to the following should fix the issue:\r\n```python\r\nclose_code = int(message.get(\"code\") or status.WS_1000_NORMAL_CLOSURE)               \r\n````\r\n</div>\n", "before_files": [{"content": "import asyncio\nimport json\nimport typing\n\nfrom starlette import status\nfrom starlette.concurrency import run_in_threadpool\nfrom starlette.exceptions import HTTPException\nfrom starlette.requests import Request\nfrom starlette.responses import PlainTextResponse, Response\nfrom starlette.types import Message, Receive, Scope, Send\nfrom starlette.websockets import WebSocket\n\n\nclass HTTPEndpoint:\n    def __init__(self, scope: Scope, receive: Receive, send: Send) -> None:\n        assert scope[\"type\"] == \"http\"\n        self.scope = scope\n        self.receive = receive\n        self.send = send\n        self._allowed_methods = [\n            method\n            for method in (\"GET\", \"HEAD\", \"POST\", \"PUT\", \"PATCH\", \"DELETE\", \"OPTIONS\")\n            if getattr(self, method.lower(), None) is not None\n        ]\n\n    def __await__(self) -> typing.Generator:\n        return self.dispatch().__await__()\n\n    async def dispatch(self) -> None:\n        request = Request(self.scope, receive=self.receive)\n        handler_name = (\n            \"get\"\n            if request.method == \"HEAD\" and not hasattr(self, \"head\")\n            else request.method.lower()\n        )\n\n        handler: typing.Callable[[Request], typing.Any] = getattr(\n            self, handler_name, self.method_not_allowed\n        )\n        is_async = asyncio.iscoroutinefunction(handler)\n        if is_async:\n            response = await handler(request)\n        else:\n            response = await run_in_threadpool(handler, request)\n        await response(self.scope, self.receive, self.send)\n\n    async def method_not_allowed(self, request: Request) -> Response:\n        # If we're running inside a starlette application then raise an\n        # exception, so that the configurable exception handler can deal with\n        # returning the response. For plain ASGI apps, just return the response.\n        headers = {\"Allow\": \", \".join(self._allowed_methods)}\n        if \"app\" in self.scope:\n            raise HTTPException(status_code=405, headers=headers)\n        return PlainTextResponse(\"Method Not Allowed\", status_code=405, headers=headers)\n\n\nclass WebSocketEndpoint:\n\n    encoding: typing.Optional[str] = None  # May be \"text\", \"bytes\", or \"json\".\n\n    def __init__(self, scope: Scope, receive: Receive, send: Send) -> None:\n        assert scope[\"type\"] == \"websocket\"\n        self.scope = scope\n        self.receive = receive\n        self.send = send\n\n    def __await__(self) -> typing.Generator:\n        return self.dispatch().__await__()\n\n    async def dispatch(self) -> None:\n        websocket = WebSocket(self.scope, receive=self.receive, send=self.send)\n        await self.on_connect(websocket)\n\n        close_code = status.WS_1000_NORMAL_CLOSURE\n\n        try:\n            while True:\n                message = await websocket.receive()\n                if message[\"type\"] == \"websocket.receive\":\n                    data = await self.decode(websocket, message)\n                    await self.on_receive(websocket, data)\n                elif message[\"type\"] == \"websocket.disconnect\":\n                    close_code = int(message.get(\"code\", status.WS_1000_NORMAL_CLOSURE))\n                    break\n        except Exception as exc:\n            close_code = status.WS_1011_INTERNAL_ERROR\n            raise exc\n        finally:\n            await self.on_disconnect(websocket, close_code)\n\n    async def decode(self, websocket: WebSocket, message: Message) -> typing.Any:\n\n        if self.encoding == \"text\":\n            if \"text\" not in message:\n                await websocket.close(code=status.WS_1003_UNSUPPORTED_DATA)\n                raise RuntimeError(\"Expected text websocket messages, but got bytes\")\n            return message[\"text\"]\n\n        elif self.encoding == \"bytes\":\n            if \"bytes\" not in message:\n                await websocket.close(code=status.WS_1003_UNSUPPORTED_DATA)\n                raise RuntimeError(\"Expected bytes websocket messages, but got text\")\n            return message[\"bytes\"]\n\n        elif self.encoding == \"json\":\n            if message.get(\"text\") is not None:\n                text = message[\"text\"]\n            else:\n                text = message[\"bytes\"].decode(\"utf-8\")\n\n            try:\n                return json.loads(text)\n            except json.decoder.JSONDecodeError:\n                await websocket.close(code=status.WS_1003_UNSUPPORTED_DATA)\n                raise RuntimeError(\"Malformed JSON data received.\")\n\n        assert (\n            self.encoding is None\n        ), f\"Unsupported 'encoding' attribute {self.encoding}\"\n        return message[\"text\"] if message.get(\"text\") else message[\"bytes\"]\n\n    async def on_connect(self, websocket: WebSocket) -> None:\n        \"\"\"Override to handle an incoming websocket connection\"\"\"\n        await websocket.accept()\n\n    async def on_receive(self, websocket: WebSocket, data: typing.Any) -> None:\n        \"\"\"Override to handle an incoming websocket message\"\"\"\n\n    async def on_disconnect(self, websocket: WebSocket, close_code: int) -> None:\n        \"\"\"Override to handle a disconnecting websocket\"\"\"\n", "path": "starlette/endpoints.py"}], "after_files": [{"content": "import asyncio\nimport json\nimport typing\n\nfrom starlette import status\nfrom starlette.concurrency import run_in_threadpool\nfrom starlette.exceptions import HTTPException\nfrom starlette.requests import Request\nfrom starlette.responses import PlainTextResponse, Response\nfrom starlette.types import Message, Receive, Scope, Send\nfrom starlette.websockets import WebSocket\n\n\nclass HTTPEndpoint:\n    def __init__(self, scope: Scope, receive: Receive, send: Send) -> None:\n        assert scope[\"type\"] == \"http\"\n        self.scope = scope\n        self.receive = receive\n        self.send = send\n        self._allowed_methods = [\n            method\n            for method in (\"GET\", \"HEAD\", \"POST\", \"PUT\", \"PATCH\", \"DELETE\", \"OPTIONS\")\n            if getattr(self, method.lower(), None) is not None\n        ]\n\n    def __await__(self) -> typing.Generator:\n        return self.dispatch().__await__()\n\n    async def dispatch(self) -> None:\n        request = Request(self.scope, receive=self.receive)\n        handler_name = (\n            \"get\"\n            if request.method == \"HEAD\" and not hasattr(self, \"head\")\n            else request.method.lower()\n        )\n\n        handler: typing.Callable[[Request], typing.Any] = getattr(\n            self, handler_name, self.method_not_allowed\n        )\n        is_async = asyncio.iscoroutinefunction(handler)\n        if is_async:\n            response = await handler(request)\n        else:\n            response = await run_in_threadpool(handler, request)\n        await response(self.scope, self.receive, self.send)\n\n    async def method_not_allowed(self, request: Request) -> Response:\n        # If we're running inside a starlette application then raise an\n        # exception, so that the configurable exception handler can deal with\n        # returning the response. For plain ASGI apps, just return the response.\n        headers = {\"Allow\": \", \".join(self._allowed_methods)}\n        if \"app\" in self.scope:\n            raise HTTPException(status_code=405, headers=headers)\n        return PlainTextResponse(\"Method Not Allowed\", status_code=405, headers=headers)\n\n\nclass WebSocketEndpoint:\n\n    encoding: typing.Optional[str] = None  # May be \"text\", \"bytes\", or \"json\".\n\n    def __init__(self, scope: Scope, receive: Receive, send: Send) -> None:\n        assert scope[\"type\"] == \"websocket\"\n        self.scope = scope\n        self.receive = receive\n        self.send = send\n\n    def __await__(self) -> typing.Generator:\n        return self.dispatch().__await__()\n\n    async def dispatch(self) -> None:\n        websocket = WebSocket(self.scope, receive=self.receive, send=self.send)\n        await self.on_connect(websocket)\n\n        close_code = status.WS_1000_NORMAL_CLOSURE\n\n        try:\n            while True:\n                message = await websocket.receive()\n                if message[\"type\"] == \"websocket.receive\":\n                    data = await self.decode(websocket, message)\n                    await self.on_receive(websocket, data)\n                elif message[\"type\"] == \"websocket.disconnect\":\n                    close_code = int(\n                        message.get(\"code\") or status.WS_1000_NORMAL_CLOSURE\n                    )\n                    break\n        except Exception as exc:\n            close_code = status.WS_1011_INTERNAL_ERROR\n            raise exc\n        finally:\n            await self.on_disconnect(websocket, close_code)\n\n    async def decode(self, websocket: WebSocket, message: Message) -> typing.Any:\n\n        if self.encoding == \"text\":\n            if \"text\" not in message:\n                await websocket.close(code=status.WS_1003_UNSUPPORTED_DATA)\n                raise RuntimeError(\"Expected text websocket messages, but got bytes\")\n            return message[\"text\"]\n\n        elif self.encoding == \"bytes\":\n            if \"bytes\" not in message:\n                await websocket.close(code=status.WS_1003_UNSUPPORTED_DATA)\n                raise RuntimeError(\"Expected bytes websocket messages, but got text\")\n            return message[\"bytes\"]\n\n        elif self.encoding == \"json\":\n            if message.get(\"text\") is not None:\n                text = message[\"text\"]\n            else:\n                text = message[\"bytes\"].decode(\"utf-8\")\n\n            try:\n                return json.loads(text)\n            except json.decoder.JSONDecodeError:\n                await websocket.close(code=status.WS_1003_UNSUPPORTED_DATA)\n                raise RuntimeError(\"Malformed JSON data received.\")\n\n        assert (\n            self.encoding is None\n        ), f\"Unsupported 'encoding' attribute {self.encoding}\"\n        return message[\"text\"] if message.get(\"text\") else message[\"bytes\"]\n\n    async def on_connect(self, websocket: WebSocket) -> None:\n        \"\"\"Override to handle an incoming websocket connection\"\"\"\n        await websocket.accept()\n\n    async def on_receive(self, websocket: WebSocket, data: typing.Any) -> None:\n        \"\"\"Override to handle an incoming websocket message\"\"\"\n\n    async def on_disconnect(self, websocket: WebSocket, close_code: int) -> None:\n        \"\"\"Override to handle a disconnecting websocket\"\"\"\n", "path": "starlette/endpoints.py"}]}