Repository: python-telegram-bot/python-telegram-bot

Issue:
UnboundLocalError when submitting smth else then an Update to the webhook
https://github.com/python-telegram-bot/python-telegram-bot/blob/dd9af64a5c99c2518ef86027e008cdb8659dd1f5/telegram/ext/_utils/webhookhandler.py#L141-L148

I realized that when putting a not decodable "Update", the appropriate log is shown, but since the code continues to run, the other party receives a non descriptive 500 Internal Server Error and in the traceback an UnboundLocalError appears.

This could be easily fixed with adding `update = None` to line 149, but this means the sending party receives 200 OK while it is certainly not OK.

However, if I add a descriptive error here, bad actors could realize that they hit a telegram bot webhook and try to abuse it/spam it.  Do we want that?

If people want to protect their webhooks, they should add the secret anyway. There we however raise if the wrong/none token has been supplied, already exposing that a PTB webhook is located behind the URL...

<details>
 <summary>Traceback if you want to look at it</summary>

```
DEBUG:telegram.ext.Updater:0.0.0.0 - Exception in TelegramHandler
Traceback (most recent call last):
  File "/home/poolitzer/python-telegram-bot/venv/lib/python3.11/site-packages/tornado/web.py", line 1786, in _execute
    result = await result
             ^^^^^^^^^^^^
  File "/home/poolitzer/python-telegram-bot/telegram/ext/_utils/webhookhandler.py", line 159, in post
    if update:
       ^^^^^^
UnboundLocalError: cannot access local variable 'update' where it is not associated with a value
```

</details>



Discussion:
I agree that we can handle this more gracefully and I also agree that we should not return 200 to the sender in case the update can not be parsed. I'm okay with a descriptive error message. Something generic like "Update could not be processed" is probably unlikely to be very interpretable unless you know that you're working with a webhook of a telegram bot.

Maybe something like

```python
try:
    update = Update.de_json(…)
except:
    # log
    update = None

if update:
    # process
else:
    # reply to sender with 400 "Update could not be processed"
```

?
@Bibo-Joshi Sure, good idea.

Resolving patch:
diff --git a/telegram/ext/_utils/webhookhandler.py b/telegram/ext/_utils/webhookhandler.py
--- a/telegram/ext/_utils/webhookhandler.py
+++ b/telegram/ext/_utils/webhookhandler.py
@@ -146,6 +146,9 @@ async def post(self) -> None:
                 "Received data was *not* processed!",
                 exc_info=exc,
             )
+            raise tornado.web.HTTPError(
+                HTTPStatus.BAD_REQUEST, reason="Update could not be processed"
+            ) from exc
 
         if update:
             _LOGGER.debug(


Test patch:
diff --git a/tests/ext/test_updater.py b/tests/ext/test_updater.py
--- a/tests/ext/test_updater.py
+++ b/tests/ext/test_updater.py
@@ -63,6 +63,7 @@ class TestUpdater:
     cb_handler_called = None
     offset = 0
     test_flag = False
+    response_text = "<html><title>{1}: {0}</title><body>{1}: {0}</body></html>"
 
     @pytest.fixture(autouse=True)
     def _reset(self):
@@ -732,11 +733,10 @@ async def set_webhook(*args, **kwargs):
 
             if secret_token:
                 # Returns Forbidden if no secret token is set
-                response_text = "<html><title>403: {0}</title><body>403: {0}</body></html>"
                 response = await send_webhook_message(ip, port, update.to_json(), "TOKEN")
                 assert response.status_code == HTTPStatus.FORBIDDEN
-                assert response.text == response_text.format(
-                    "Request did not include the secret token"
+                assert response.text == self.response_text.format(
+                    "Request did not include the secret token", HTTPStatus.FORBIDDEN
                 )
 
                 # Returns Forbidden if the secret token is wrong
@@ -744,7 +744,9 @@ async def set_webhook(*args, **kwargs):
                     ip, port, update.to_json(), "TOKEN", secret_token="NotTheSecretToken"
                 )
                 assert response.status_code == HTTPStatus.FORBIDDEN
-                assert response.text == response_text.format("Request had the wrong secret token")
+                assert response.text == self.response_text.format(
+                    "Request had the wrong secret token", HTTPStatus.FORBIDDEN
+                )
 
             await updater.stop()
             assert not updater.running
@@ -1071,11 +1073,15 @@ def de_json_fails(*args, **kwargs):
             # Now, we send an update to the server
             update = make_message_update("Webhook")
             with caplog.at_level(logging.CRITICAL):
-                await send_webhook_message(ip, port, update.to_json(), "TOKEN")
+                response = await send_webhook_message(ip, port, update.to_json(), "TOKEN")
 
             assert len(caplog.records) == 1
             assert caplog.records[-1].getMessage().startswith("Something went wrong processing")
             assert caplog.records[-1].name == "telegram.ext.Updater"
+            assert response.status_code == 400
+            assert response.text == self.response_text.format(
+                "Update could not be processed", HTTPStatus.BAD_REQUEST
+            )
 
             # Make sure that everything works fine again when receiving proper updates
             caplog.clear()