Skip to content

Commit 9fcd20c

Browse files
committed
Fix #829 by adding the default encoding
1 parent f3053d6 commit 9fcd20c

File tree

6 files changed

+68
-7
lines changed

6 files changed

+68
-7
lines changed

slack/web/base_client.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -475,7 +475,7 @@ def _perform_urllib_http_request(
475475
resp = urlopen( # skipcq: BAN-B310
476476
req, context=self.ssl, timeout=self.timeout
477477
)
478-
charset = resp.headers.get_content_charset()
478+
charset = resp.headers.get_content_charset() or "utf-8"
479479
body: str = resp.read().decode(charset) # read the response body here
480480
return {"status": resp.code, "headers": resp.headers, "body": body}
481481
raise SlackRequestError(f"Invalid URL detected: {url}")
@@ -485,7 +485,7 @@ def _perform_urllib_http_request(
485485
# for compatibility with aiohttp
486486
resp["headers"]["Retry-After"] = resp["headers"]["retry-after"]
487487

488-
charset = e.headers.get_content_charset()
488+
charset = e.headers.get_content_charset() or "utf-8"
489489
body: str = e.read().decode(charset) # read the response body here
490490
resp["body"] = body
491491
return resp

slack/webhook/client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ def _perform_http_request(
144144
return resp
145145

146146
except HTTPError as e:
147-
charset = e.headers.get_content_charset()
147+
charset = e.headers.get_content_charset() or "utf-8"
148148
body: str = e.read().decode(charset) # read the response body here
149149
resp = WebhookResponse(
150150
url=url, status_code=e.code, body=body, headers=e.headers,

tests/web/mock_web_api_server.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ class MockHandler(SimpleHTTPRequestHandler):
2020

2121
html_response_body = '<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n<html><head>\n<title>404 Not Found</title>\n</head><body>\n<h1>Not Found</h1>\n<p>The requested URL /api/team.info was not found on this server.</p>\n</body></html>\n'
2222

23+
error_html_response_body = '<!DOCTYPE html>\n<html lang="en">\n<head>\n\t<meta charset="utf-8">\n\t<title>Server Error | Slack</title>\n\t<meta name="author" content="Slack">\n\t<style></style>\n</head>\n<body>\n\t<nav class="top persistent">\n\t\t<a href="https://status.slack.com/" class="logo" data-qa="logo"></a>\n\t</nav>\n\t<div id="page">\n\t\t<div id="page_contents">\n\t\t\t<h1>\n\t\t\t\t<svg width="30px" height="27px" viewBox="0 0 60 54" class="warning_icon"><path d="" fill="#D94827"/></svg>\n\t\t\t\tServer Error\n\t\t\t</h1>\n\t\t\t<div class="card">\n\t\t\t\t<p>It seems like there’s a problem connecting to our servers, and we’re investigating the issue.</p>\n\t\t\t\t<p>Please <a href="https://status.slack.com/">check our Status page for updates</a>.</p>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n\t<script type="text/javascript">\n\t\tif (window.desktop) {\n\t\t\tdocument.documentElement.className = \'desktop\';\n\t\t}\n\n\t\tvar FIVE_MINS = 5 * 60 * 1000;\n\t\tvar TEN_MINS = 10 * 60 * 1000;\n\n\t\tfunction randomBetween(min, max) {\n\t\t\treturn Math.floor(Math.random() * (max - (min + 1))) + min;\n\t\t}\n\n\t\twindow.setTimeout(function () {\n\t\t\twindow.location.reload(true);\n\t\t}, randomBetween(FIVE_MINS, TEN_MINS));\n\t</script>\n</body>\n</html>'
24+
2325
def is_valid_user_agent(self):
2426
user_agent = self.headers["User-Agent"]
2527
return self.pattern_for_language.search(user_agent) \
@@ -102,11 +104,21 @@ def _handle(self):
102104

103105
if pattern == "html_response":
104106
self.send_response(404)
105-
self.set_common_headers()
107+
self.send_header("content-type", "text/html;charset=utf-8")
108+
self.send_header("connection", "close")
109+
self.end_headers()
106110
self.wfile.write(self.html_response_body.encode("utf-8"))
107111
self.wfile.close()
108112
return
109113

114+
if pattern == "error_html_response":
115+
self.send_response(503)
116+
self.send_header("connection", "close")
117+
self.end_headers()
118+
self.wfile.write(self.error_html_response_body.encode("utf-8"))
119+
self.wfile.close()
120+
return
121+
110122
if pattern.startswith("user-agent"):
111123
elements = pattern.split(" ")
112124
prefix, suffix = elements[1], elements[-1]
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import unittest
2+
3+
import slack.errors as err
4+
from slack import WebClient
5+
from tests.helpers import async_test
6+
from tests.web.mock_web_api_server import (
7+
setup_mock_web_api_server,
8+
cleanup_mock_web_api_server,
9+
)
10+
11+
12+
class TestWebClient_Issue_829(unittest.TestCase):
13+
def setUp(self):
14+
setup_mock_web_api_server(self)
15+
self.client = WebClient(token="xoxp-1234", base_url="http://localhost:8888", )
16+
self.async_client = WebClient(
17+
token="xoxp-1234", run_async=True, base_url="http://localhost:8888",
18+
)
19+
20+
def tearDown(self):
21+
cleanup_mock_web_api_server(self)
22+
23+
def test_html_response_body_issue_829(self):
24+
client = WebClient(base_url="http://localhost:8888")
25+
try:
26+
client.users_list(token="xoxb-error_html_response")
27+
self.fail("SlackApiError expected here")
28+
except err.SlackApiError as e:
29+
self.assertTrue(
30+
str(e).startswith("Failed to parse the response body: Expecting value: "),
31+
e,
32+
)
33+
34+
@async_test
35+
async def test_html_response_body_issue_829_async(self):
36+
client = WebClient(base_url="http://localhost:8888", run_async=True)
37+
try:
38+
await client.users_list(token="xoxb-error_html_response")
39+
self.fail("SlackApiError expected here")
40+
except err.SlackApiError as e:
41+
self.assertEqual(
42+
"The request to the Slack API failed.\n"
43+
"The server responded with: {}",
44+
str(e)
45+
)

tests/webhook/mock_web_api_server.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ class MockHandler(SimpleHTTPRequestHandler):
1616
pattern_for_language = re.compile("python/(\\S+)", re.IGNORECASE)
1717
pattern_for_package_identifier = re.compile("slackclient/(\\S+)")
1818

19+
error_html_response_body = '<!DOCTYPE html>\n<html lang="en">\n<head>\n\t<meta charset="utf-8">\n\t<title>Server Error | Slack</title>\n\t<meta name="author" content="Slack">\n\t<style></style>\n</head>\n<body>\n\t<nav class="top persistent">\n\t\t<a href="https://status.slack.com/" class="logo" data-qa="logo"></a>\n\t</nav>\n\t<div id="page">\n\t\t<div id="page_contents">\n\t\t\t<h1>\n\t\t\t\t<svg width="30px" height="27px" viewBox="0 0 60 54" class="warning_icon"><path d="" fill="#D94827"/></svg>\n\t\t\t\tServer Error\n\t\t\t</h1>\n\t\t\t<div class="card">\n\t\t\t\t<p>It seems like there’s a problem connecting to our servers, and we’re investigating the issue.</p>\n\t\t\t\t<p>Please <a href="https://status.slack.com/">check our Status page for updates</a>.</p>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n\t<script type="text/javascript">\n\t\tif (window.desktop) {\n\t\t\tdocument.documentElement.className = \'desktop\';\n\t\t}\n\n\t\tvar FIVE_MINS = 5 * 60 * 1000;\n\t\tvar TEN_MINS = 10 * 60 * 1000;\n\n\t\tfunction randomBetween(min, max) {\n\t\t\treturn Math.floor(Math.random() * (max - (min + 1))) + min;\n\t\t}\n\n\t\twindow.setTimeout(function () {\n\t\t\twindow.location.reload(true);\n\t\t}, randomBetween(FIVE_MINS, TEN_MINS));\n\t</script>\n</body>\n</html>'
20+
1921
def is_valid_user_agent(self):
2022
user_agent = self.headers["User-Agent"]
2123
return self.pattern_for_language.search(user_agent) \
@@ -51,8 +53,10 @@ def do_POST(self):
5153

5254
if self.path == "/error":
5355
self.send_response(HTTPStatus.INTERNAL_SERVER_ERROR)
54-
self.set_common_headers()
55-
self.wfile.write("error".encode("utf-8"))
56+
self.send_header("content-type", "text/html")
57+
self.send_header("connection", "close")
58+
self.end_headers()
59+
self.wfile.write(self.error_html_response_body.encode("utf-8"))
5660
self.wfile.close()
5761
return
5862

tests/webhook/test_webhook.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ def test_error_response(self):
166166
client = WebhookClient(url="http://localhost:8888/error")
167167
resp: WebhookResponse = client.send_dict({"text": "hello!"})
168168
self.assertEqual(500, resp.status_code)
169-
self.assertEqual("error", resp.body)
169+
self.assertTrue(resp.body.startswith("<!DOCTYPE html>"))
170170

171171
def test_proxy_issue_714(self):
172172
client = WebhookClient(url="http://localhost:8888", proxy="http://invalid-host:9999")

0 commit comments

Comments
 (0)