We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Cannot inject websocket with binary or string content.
#### Problem Description
mitmproxy attempts to parse the injected websocket binary data as text, and replaces the binary data if it cannot be decoded into text, changing the injected websocket message. Also, when a string is given instead, there is error:
File "\mitmproxy\proxy\layers\websocket.py", line 230, in msg
    data_str = data.decode(errors="replace")
AttributeError: 'str' object has no attribute 'decode'

#### Steps to reproduce the behavior:
1. from mitmproxy.ctx import master
2. master.commands.call("inject.websocket", flow, False, bytes([i for i in range(256)])) # No error, but message contents are changed
3. master.commands.call("inject.websocket", flow, False, "string") # AttributeError

#### System Information
Mitmproxy: 7.0.2
Python:    3.9.6
OpenSSL:   OpenSSL 1.1.1k  25 Mar 2021
Platform:  Windows-10-10.0.19043-SP0


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `examples/addons/websocket-inject-message.py`
Content:
```
1 """
2 Inject a WebSocket message into a running connection.
3 
4 This example shows how to inject a WebSocket message into a running connection.
5 """
6 import asyncio
7 
8 from mitmproxy import ctx, http
9 
10 
11 # Simple example: Inject a message as a response to an event
12 
13 def websocket_message(flow: http.HTTPFlow):
14     assert flow.websocket is not None  # make type checker happy
15     last_message = flow.websocket.messages[-1]
16     if b"secret" in last_message.content:
17         last_message.drop()
18         ctx.master.commands.call("inject.websocket", flow, last_message.from_client, "ssssssh")
19 
20 
21 # Complex example: Schedule a periodic timer
22 
23 async def inject_async(flow: http.HTTPFlow):
24     msg = "hello from mitmproxy! "
25     assert flow.websocket is not None  # make type checker happy
26     while flow.websocket.timestamp_end is None:
27         ctx.master.commands.call("inject.websocket", flow, True, msg)
28         await asyncio.sleep(1)
29         msg = msg[1:] + msg[:1]
30 
31 
32 def websocket_start(flow: http.HTTPFlow):
33     asyncio.create_task(inject_async(flow))
34
```
--- 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()

```

diff --git a/examples/addons/websocket-inject-message.py b/examples/addons/websocket-inject-message.py
--- a/examples/addons/websocket-inject-message.py
+++ b/examples/addons/websocket-inject-message.py
@@ -13,9 +13,9 @@
 def websocket_message(flow: http.HTTPFlow):
     assert flow.websocket is not None  # make type checker happy
     last_message = flow.websocket.messages[-1]
-    if b"secret" in last_message.content:
+    if last_message.is_text and "secret" in last_message.text:
         last_message.drop()
-        ctx.master.commands.call("inject.websocket", flow, last_message.from_client, "ssssssh")
+        ctx.master.commands.call("inject.websocket", flow, last_message.from_client, "ssssssh".encode())
 
 
 # Complex example: Schedule a periodic timer
@@ -24,7 +24,7 @@
     msg = "hello from mitmproxy! "
     assert flow.websocket is not None  # make type checker happy
     while flow.websocket.timestamp_end is None:
-        ctx.master.commands.call("inject.websocket", flow, True, msg)
+        ctx.master.commands.call("inject.websocket", flow, True, msg.encode())
         await asyncio.sleep(1)
         msg = msg[1:] + msg[:1]

{"golden_diff": "diff --git a/examples/addons/websocket-inject-message.py b/examples/addons/websocket-inject-message.py\n--- a/examples/addons/websocket-inject-message.py\n+++ b/examples/addons/websocket-inject-message.py\n@@ -13,9 +13,9 @@\n def websocket_message(flow: http.HTTPFlow):\n     assert flow.websocket is not None  # make type checker happy\n     last_message = flow.websocket.messages[-1]\n-    if b\"secret\" in last_message.content:\n+    if last_message.is_text and \"secret\" in last_message.text:\n         last_message.drop()\n-        ctx.master.commands.call(\"inject.websocket\", flow, last_message.from_client, \"ssssssh\")\n+        ctx.master.commands.call(\"inject.websocket\", flow, last_message.from_client, \"ssssssh\".encode())\n \n \n # Complex example: Schedule a periodic timer\n@@ -24,7 +24,7 @@\n     msg = \"hello from mitmproxy! \"\n     assert flow.websocket is not None  # make type checker happy\n     while flow.websocket.timestamp_end is None:\n-        ctx.master.commands.call(\"inject.websocket\", flow, True, msg)\n+        ctx.master.commands.call(\"inject.websocket\", flow, True, msg.encode())\n         await asyncio.sleep(1)\n         msg = msg[1:] + msg[:1]\n", "issue": "Cannot inject websocket with binary or string content.\n#### Problem Description\r\nmitmproxy attempts to parse the injected websocket binary data as text, and replaces the binary data if it cannot be decoded into text, changing the injected websocket message. Also, when a string is given instead, there is error:\r\nFile \"\\mitmproxy\\proxy\\layers\\websocket.py\", line 230, in msg\r\n    data_str = data.decode(errors=\"replace\")\r\nAttributeError: 'str' object has no attribute 'decode'\r\n\r\n#### Steps to reproduce the behavior:\r\n1. from mitmproxy.ctx import master\r\n2. master.commands.call(\"inject.websocket\", flow, False, bytes([i for i in range(256)])) # No error, but message contents are changed\r\n3. master.commands.call(\"inject.websocket\", flow, False, \"string\") # AttributeError\r\n\r\n#### System Information\r\nMitmproxy: 7.0.2\r\nPython:    3.9.6\r\nOpenSSL:   OpenSSL 1.1.1k  25 Mar 2021\r\nPlatform:  Windows-10-10.0.19043-SP0\r\n\n", "before_files": [{"content": "\"\"\"\nInject a WebSocket message into a running connection.\n\nThis example shows how to inject a WebSocket message into a running connection.\n\"\"\"\nimport asyncio\n\nfrom mitmproxy import ctx, http\n\n\n# Simple example: Inject a message as a response to an event\n\ndef websocket_message(flow: http.HTTPFlow):\n    assert flow.websocket is not None  # make type checker happy\n    last_message = flow.websocket.messages[-1]\n    if b\"secret\" in last_message.content:\n        last_message.drop()\n        ctx.master.commands.call(\"inject.websocket\", flow, last_message.from_client, \"ssssssh\")\n\n\n# Complex example: Schedule a periodic timer\n\nasync def inject_async(flow: http.HTTPFlow):\n    msg = \"hello from mitmproxy! \"\n    assert flow.websocket is not None  # make type checker happy\n    while flow.websocket.timestamp_end is None:\n        ctx.master.commands.call(\"inject.websocket\", flow, True, msg)\n        await asyncio.sleep(1)\n        msg = msg[1:] + msg[:1]\n\n\ndef websocket_start(flow: http.HTTPFlow):\n    asyncio.create_task(inject_async(flow))\n", "path": "examples/addons/websocket-inject-message.py"}], "after_files": [{"content": "\"\"\"\nInject a WebSocket message into a running connection.\n\nThis example shows how to inject a WebSocket message into a running connection.\n\"\"\"\nimport asyncio\n\nfrom mitmproxy import ctx, http\n\n\n# Simple example: Inject a message as a response to an event\n\ndef websocket_message(flow: http.HTTPFlow):\n    assert flow.websocket is not None  # make type checker happy\n    last_message = flow.websocket.messages[-1]\n    if last_message.is_text and \"secret\" in last_message.text:\n        last_message.drop()\n        ctx.master.commands.call(\"inject.websocket\", flow, last_message.from_client, \"ssssssh\".encode())\n\n\n# Complex example: Schedule a periodic timer\n\nasync def inject_async(flow: http.HTTPFlow):\n    msg = \"hello from mitmproxy! \"\n    assert flow.websocket is not None  # make type checker happy\n    while flow.websocket.timestamp_end is None:\n        ctx.master.commands.call(\"inject.websocket\", flow, True, msg.encode())\n        await asyncio.sleep(1)\n        msg = msg[1:] + msg[:1]\n\n\ndef websocket_start(flow: http.HTTPFlow):\n    asyncio.create_task(inject_async(flow))\n", "path": "examples/addons/websocket-inject-message.py"}]}