# Buggy code
def _perform_http_request(
    self, *, body: Dict[str, any], headers: Dict[str, str]
) -> WebhookResponse:
    """Performs an HTTP request and parses the response.
    :param url: a complete URL to send data (e.g., https://hooks.slack.com/XXX)
    :param body: request body data
    :param headers: complete set of request headers
    :return: API response
    """
    body = json.dumps(body)
    headers["Content-Type"] = "application/json;charset=utf-8"

    if self.logger.level <= logging.DEBUG:
        self.logger.debug(
            f"Sending a request - url: {self.url}, body: {body}, headers: {headers}"
        )
    try:
        url = self.url
        # for security (BAN-B310)
        if url.lower().startswith("http"):
            req = Request(
                method="POST", url=url, data=body.encode("utf-8"), headers=headers
            )
            if self.proxy is not None:
                host = re.sub("^https?://", "", self.proxy)
                req.set_proxy(host, "http")
                req.set_proxy(host, "https")
        else:
            raise SlackRequestError(f"Invalid URL detected: {url}")

        # NOTE: BAN-B310 is already checked above
        resp: HTTPResponse = urlopen(  # skipcq: BAN-B310
            req,
            context=self.ssl,
            timeout=self.timeout,
        )
        charset: str = resp.headers.get_content_charset() or "utf-8"
        response_body: str = resp.read().decode(charset)
        resp = WebhookResponse(
            url=url,
            status_code=resp.status,
            body=response_body,
            headers=resp.headers,
        )
        _debug_log_response(self.logger, resp)
        return resp

    except HTTPError as e:
        charset = e.headers.get_content_charset()
        body: str = e.read().decode(charset)  # read the response body here
        resp = WebhookResponse(
            url=url,
            status_code=e.code,
            body=body,
            headers=e.headers,
        )
        if e.code == 429:
            # for backward-compatibility with WebClient (v.2.5.0 or older)
            resp.headers["Retry-After"] = resp.headers["retry-after"]
        _debug_log_response(self.logger, resp)
        return resp

    except Exception as err:
        self.logger.error(f"Failed to send a request to Slack API server: {err}")
        raise err


# Traceback (urllib.error.URLError)
Traceback (most recent call last):
File "/usr/local/lib/python3.8/urllib/request.py", line 1350, in do_open
h.request(req.get_method(), req.selector, req.data, headers,
File "/usr/local/lib/python3.8/http/client.py", line 1255, in request
self._send_request(method, url, body, headers, encode_chunked)
File "/usr/local/lib/python3.8/http/client.py", line 1301, in _send_request
self.endheaders(body, encode_chunked=encode_chunked)
File "/usr/local/lib/python3.8/http/client.py", line 1250, in endheaders
self._send_output(message_body, encode_chunked=encode_chunked)
File "/usr/local/lib/python3.8/http/client.py", line 1010, in _send_output
self.send(msg)
File "/usr/local/lib/python3.8/http/client.py", line 950, in send
self.connect()
File "/usr/local/lib/python3.8/http/client.py", line 1417, in connect
super().connect()
File "/usr/local/lib/python3.8/http/client.py", line 921, in connect
self.sock = self._create_connection(
File "/usr/local/lib/python3.8/socket.py", line 787, in create_connection
for res in getaddrinfo(host, port, 0, SOCK_STREAM):
File "/usr/local/lib/python3.8/socket.py", line 918, in getaddrinfo
for res in _socket.getaddrinfo(host, port, family, type, proto, flags):
socket.gaierror: [Errno -2] Name or service not known

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python3.8/site-packages/slack/web/client.py", line 881, in chat_postMessage
return self.api_call("chat.postMessage", json=kwargs)
File "/usr/local/lib/python3.8/site-packages/slack/web/base_client.py", line 150, in api_call
return self._sync_send(api_url=api_url, req_args=req_args)
File "/usr/local/lib/python3.8/site-packages/slack/web/base_client.py", line 241, in _sync_send
return self._urllib_api_call(
File "/usr/local/lib/python3.8/site-packages/slack/web/base_client.py", line 352, in _urllib_api_call
response = self._perform_urllib_http_request(url=url, args=request_args)
File "/usr/local/lib/python3.8/site-packages/slack/web/base_client.py", line 489, in _perform_urllib_http_request
raise err
File "/usr/local/lib/python3.8/site-packages/slack/web/base_client.py", line 469, in _perform_urllib_http_request
resp: HTTPResponse = urlopen(  # skipcq: BAN-B310
File "/usr/local/lib/python3.8/urllib/request.py", line 222, in urlopen
return opener.open(url, data, timeout)
File "/usr/local/lib/python3.8/urllib/request.py", line 531, in open
response = meth(req, response)
File "/usr/local/lib/python3.8/urllib/request.py", line 640, in http_response
response = self.parent.error(
File "/usr/local/lib/python3.8/urllib/request.py", line 563, in error
result = self._call_chain(*args)
File "/usr/local/lib/python3.8/urllib/request.py", line 502, in _call_chain
result = func(*args)
File "/usr/local/lib/python3.8/urllib/request.py", line 755, in http_error_302
return self.parent.open(new, timeout=req.timeout)
File "/usr/local/lib/python3.8/urllib/request.py", line 525, in open
response = self._open(req, data)
File "/usr/local/lib/python3.8/urllib/request.py", line 542, in _open
result = self._call_chain(self.handle_open, protocol, protocol +
File "/usr/local/lib/python3.8/urllib/request.py", line 502, in _call_chain
result = func(*args)
File "/usr/local/lib/python3.8/urllib/request.py", line 1393, in https_open
return self.do_open(http.client.HTTPSConnection, req,
File "/usr/local/lib/python3.8/urllib/request.py", line 1353, in do_open
raise URLError(err)
urllib.error.URLError: <urlopen error [Errno -2] Name or service not known>

# Fixed code
def _perform_http_request(
    self, *, body: Dict[str, any], headers: Dict[str, str]
) -> WebhookResponse:
    """Performs an HTTP request and parses the response.
    :param url: a complete URL to send data (e.g., https://hooks.slack.com/XXX)
    :param body: request body data
    :param headers: complete set of request headers
    :return: API response
    """
    body = json.dumps(body)
    headers["Content-Type"] = "application/json;charset=utf-8"

    if self.logger.level <= logging.DEBUG:
        self.logger.debug(
            f"Sending a request - url: {self.url}, body: {body}, headers: {headers}"
        )
    try:
        url = self.url
        opener: Optional[OpenerDirector] = None
        # for security (BAN-B310)
        if url.lower().startswith("http"):
            req = Request(
                method="POST", url=url, data=body.encode("utf-8"), headers=headers
            )
            if self.proxy is not None:
                if isinstance(self.proxy, str):
                    opener = urllib.request.build_opener(
                        ProxyHandler({"http": self.proxy, "https": self.proxy}),
                        HTTPSHandler(context=self.ssl),
                    )
                else:
                    raise SlackRequestError(
                        f"Invalid proxy detected: {self.proxy} must be a str value"
                    )
        else:
            raise SlackRequestError(f"Invalid URL detected: {url}")

        # NOTE: BAN-B310 is already checked above
        resp: Optional[HTTPResponse] = None
        if opener:
            resp = opener.open(req, timeout=self.timeout)  # skipcq: BAN-B310
        else:
            resp = urlopen(  # skipcq: BAN-B310
                req, context=self.ssl, timeout=self.timeout
            )
        charset: str = resp.headers.get_content_charset() or "utf-8"
        response_body: str = resp.read().decode(charset)
        resp = WebhookResponse(
            url=url,
            status_code=resp.status,
            body=response_body,
            headers=resp.headers,
        )
        _debug_log_response(self.logger, resp)
        return resp

    except HTTPError as e:
        charset = e.headers.get_content_charset()
        body: str = e.read().decode(charset)  # read the response body here
        resp = WebhookResponse(
            url=url,
            status_code=e.code,
            body=body,
            headers=e.headers,
        )
        if e.code == 429:
            # for backward-compatibility with WebClient (v.2.5.0 or older)
            resp.headers["Retry-After"] = resp.headers["retry-after"]
        _debug_log_response(self.logger, resp)
        return resp

    except Exception as err:
        self.logger.error(f"Failed to send a request to Slack API server: {err}")
        raise err