diff --git a/analytics/views/support.py b/analytics/views/support.py index 3d428e538f..04d233fa03 100644 --- a/analytics/views/support.py +++ b/analytics/views/support.py @@ -1,9 +1,8 @@ -import urllib from contextlib import suppress from datetime import timedelta from decimal import Decimal from typing import Any, Dict, Iterable, List, Optional, Union -from urllib.parse import urlencode +from urllib.parse import urlencode, urlparse from django.conf import settings from django.core.exceptions import ValidationError @@ -273,7 +272,7 @@ def support( for key_word in key_words: try: URLValidator()(key_word) - parse_result = urllib.parse.urlparse(key_word) + parse_result = urlparse(key_word) hostname = parse_result.hostname assert hostname is not None if parse_result.port: diff --git a/puppet/zulip_ops/files/statuspage-pusher b/puppet/zulip_ops/files/statuspage-pusher index 426a1fa650..19ba1e5865 100755 --- a/puppet/zulip_ops/files/statuspage-pusher +++ b/puppet/zulip_ops/files/statuspage-pusher @@ -5,12 +5,12 @@ import http.client import json import logging import time -import urllib.parse +from urllib.parse import urlencode def fetch_metric(metric_id: str, query: str) -> float: logging.info("Fetching %s", metric_id) - params = urllib.parse.urlencode({"query": query}) + params = urlencode({"query": query}) conn = http.client.HTTPConnection("localhost:9090") conn.request("GET", "/api/v1/query?" + params) response = conn.getresponse() diff --git a/zerver/decorator.py b/zerver/decorator.py index c8ab7410de..7084f3076b 100644 --- a/zerver/decorator.py +++ b/zerver/decorator.py @@ -1,6 +1,5 @@ import base64 import logging -import urllib from datetime import datetime from functools import wraps from io import BytesIO @@ -16,6 +15,7 @@ from typing import ( cast, overload, ) +from urllib.parse import urlparse import django_otp from django.conf import settings @@ -393,8 +393,8 @@ def zulip_redirect_to_login( resolved_login_url = resolve_url(login_url or settings.LOGIN_URL) # If the login URL is the same scheme and net location then just # use the path as the "next" url. - login_scheme, login_netloc = urllib.parse.urlparse(resolved_login_url)[:2] - current_scheme, current_netloc = urllib.parse.urlparse(path)[:2] + login_scheme, login_netloc = urlparse(resolved_login_url)[:2] + current_scheme, current_netloc = urlparse(path)[:2] if (not login_scheme or login_scheme == current_scheme) and ( not login_netloc or login_netloc == current_netloc ): diff --git a/zerver/lib/avatar.py b/zerver/lib/avatar.py index 222ae3b0ce..d46d7a7da0 100644 --- a/zerver/lib/avatar.py +++ b/zerver/lib/avatar.py @@ -1,5 +1,5 @@ -import urllib from typing import Any, Dict, Optional +from urllib.parse import urljoin from django.conf import settings from django.contrib.staticfiles.storage import staticfiles_storage @@ -135,7 +135,7 @@ def absolute_avatar_url(user_profile: UserProfile) -> str: avatar = avatar_url(user_profile) # avatar_url can return None if client_gravatar=True, however here we use the default value of False assert avatar is not None - return urllib.parse.urljoin(user_profile.realm.uri, avatar) + return urljoin(user_profile.realm.uri, avatar) def is_avatar_new(ldap_avatar: bytes, user_profile: UserProfile) -> bool: diff --git a/zerver/lib/markdown/__init__.py b/zerver/lib/markdown/__init__.py index 576f12d0c4..ebeef89c28 100644 --- a/zerver/lib/markdown/__init__.py +++ b/zerver/lib/markdown/__init__.py @@ -6,8 +6,6 @@ import logging import mimetypes import re import time -import urllib -import urllib.parse from collections import deque from dataclasses import dataclass from datetime import datetime, timezone @@ -28,7 +26,7 @@ from typing import ( Union, cast, ) -from urllib.parse import parse_qs, urlencode, urljoin, urlsplit +from urllib.parse import parse_qs, quote, urlencode, urljoin, urlparse, urlsplit, urlunparse from xml.etree.ElementTree import Element, SubElement import ahocorasick @@ -488,7 +486,7 @@ def fetch_open_graph_image(url: str) -> Optional[Dict[str, Any]]: def get_tweet_id(url: str) -> Optional[str]: - parsed_url = urllib.parse.urlparse(url) + parsed_url = urlparse(url) if not (parsed_url.netloc == "twitter.com" or parsed_url.netloc.endswith(".twitter.com")): return None to_match = parsed_url.path @@ -717,13 +715,13 @@ class InlineInterestingLinkProcessor(markdown.treeprocessors.Treeprocessor): def get_actual_image_url(self, url: str) -> str: # Add specific per-site cases to convert image-preview URLs to image URLs. # See https://github.com/zulip/zulip/issues/4658 for more information - parsed_url = urllib.parse.urlparse(url) + parsed_url = urlparse(url) if parsed_url.netloc == "github.com" or parsed_url.netloc.endswith(".github.com"): # https://github.com/zulip/zulip/blob/main/static/images/logo/zulip-icon-128x128.png -> # https://raw.githubusercontent.com/zulip/zulip/main/static/images/logo/zulip-icon-128x128.png split_path = parsed_url.path.split("/") if len(split_path) > 3 and split_path[3] == "blob": - return urllib.parse.urljoin( + return urljoin( "https://raw.githubusercontent.com", "/".join(split_path[0:3] + split_path[4:]) ) @@ -732,7 +730,7 @@ class InlineInterestingLinkProcessor(markdown.treeprocessors.Treeprocessor): def is_image(self, url: str) -> bool: if not self.zmd.image_preview_enabled: return False - parsed_url = urllib.parse.urlparse(url) + parsed_url = urlparse(url) # remove HTML URLs which end with image extensions that cannot be shorted if parsed_url.netloc == "pasteboard.co": return False @@ -744,7 +742,7 @@ class InlineInterestingLinkProcessor(markdown.treeprocessors.Treeprocessor): # wikipedia.org to point to the actual image URL. It's # structurally very similar to dropbox_image, and possibly # should be rewritten to use open graph, but has some value. - parsed_url = urllib.parse.urlparse(url) + parsed_url = urlparse(url) if parsed_url.netloc.lower().endswith(".wikipedia.org") and parsed_url.path.startswith( "/wiki/File:" ): @@ -759,7 +757,7 @@ class InlineInterestingLinkProcessor(markdown.treeprocessors.Treeprocessor): def dropbox_image(self, url: str) -> Optional[Dict[str, Any]]: # TODO: The returned Dict could possibly be a TypedDict in future. - parsed_url = urllib.parse.urlparse(url) + parsed_url = urlparse(url) if parsed_url.netloc == "dropbox.com" or parsed_url.netloc.endswith(".dropbox.com"): is_album = parsed_url.path.startswith("/sc/") or parsed_url.path.startswith("/photos/") # Only allow preview Dropbox shared links @@ -911,7 +909,7 @@ class InlineInterestingLinkProcessor(markdown.treeprocessors.Treeprocessor): "type": "mention", "start": match.start(), "end": match.end(), - "url": "https://twitter.com/" + urllib.parse.quote(screen_name), + "url": "https://twitter.com/" + quote(screen_name), "text": mention_string, } for match in re.finditer(re.escape(mention_string), text, re.IGNORECASE) @@ -1260,7 +1258,7 @@ class InlineInterestingLinkProcessor(markdown.treeprocessors.Treeprocessor): # `/user_uploads` and beginning with `user_uploads`. # This urllib construction converts the latter into # the former. - parsed_url = urllib.parse.urlsplit(urllib.parse.urljoin("/", url)) + parsed_url = urlsplit(urljoin("/", url)) host = parsed_url.netloc if host != "" and ( @@ -1568,7 +1566,7 @@ def sanitize_url(url: str) -> Optional[str]: See the docstring on markdown.inlinepatterns.LinkPattern.sanitize_url. """ try: - parts = urllib.parse.urlparse(url.replace(" ", "%20")) + parts = urlparse(url.replace(" ", "%20")) scheme, netloc, path, params, query, fragment = parts except ValueError: # Bad URL - so bad it couldn't be parsed. @@ -1580,10 +1578,10 @@ def sanitize_url(url: str) -> Optional[str]: scheme = "mailto" elif scheme == "" and netloc == "" and len(path) > 0 and path[0] == "/": # Allow domain-relative links - return urllib.parse.urlunparse(("", "", path, params, query, fragment)) + return urlunparse(("", "", path, params, query, fragment)) elif (scheme, netloc, path, params, query) == ("", "", "", "", "") and len(fragment) > 0: # Allow fragment links - return urllib.parse.urlunparse(("", "", "", "", "", fragment)) + return urlunparse(("", "", "", "", "", fragment)) # Zulip modification: If scheme is not specified, assume http:// # We re-enter sanitize_url because netloc etc. need to be re-parsed. @@ -1608,7 +1606,7 @@ def sanitize_url(url: str) -> Optional[str]: # the colon check, which would also forbid a lot of legitimate URLs. # URL passes all tests. Return URL as-is. - return urllib.parse.urlunparse((scheme, netloc, path, params, query, fragment)) + return urlunparse((scheme, netloc, path, params, query, fragment)) def url_to_a( diff --git a/zerver/lib/remote_server.py b/zerver/lib/remote_server.py index dace0e259c..4c6fa0963e 100644 --- a/zerver/lib/remote_server.py +++ b/zerver/lib/remote_server.py @@ -1,6 +1,6 @@ import logging -import urllib from typing import Any, Dict, List, Mapping, Optional, Tuple, Union +from urllib.parse import urljoin import orjson import requests @@ -88,9 +88,7 @@ def send_to_push_bouncer( assert settings.PUSH_NOTIFICATION_BOUNCER_URL is not None assert settings.ZULIP_ORG_ID is not None assert settings.ZULIP_ORG_KEY is not None - url = urllib.parse.urljoin( - settings.PUSH_NOTIFICATION_BOUNCER_URL, "/api/v1/remotes/" + endpoint - ) + url = urljoin(settings.PUSH_NOTIFICATION_BOUNCER_URL, "/api/v1/remotes/" + endpoint) api_auth = requests.auth.HTTPBasicAuth(settings.ZULIP_ORG_ID, settings.ZULIP_ORG_KEY) headers = {"User-agent": f"ZulipServer/{ZULIP_VERSION}"} diff --git a/zerver/lib/subdomains.py b/zerver/lib/subdomains.py index c583a2af4b..de6d297c28 100644 --- a/zerver/lib/subdomains.py +++ b/zerver/lib/subdomains.py @@ -1,6 +1,6 @@ import re -import urllib from typing import Optional +from urllib.parse import urlsplit from django.conf import settings from django.http import HttpRequest @@ -57,8 +57,8 @@ def is_root_domain_available() -> bool: def is_static_or_current_realm_url(url: str, realm: Optional[Realm]) -> bool: assert settings.STATIC_URL is not None - split_url = urllib.parse.urlsplit(url) - split_static_url = urllib.parse.urlsplit(settings.STATIC_URL) + split_url = urlsplit(url) + split_static_url = urlsplit(settings.STATIC_URL) # The netloc check here is important to correctness if STATIC_URL # does not contain a `/`; see the tests for why. diff --git a/zerver/lib/test_classes.py b/zerver/lib/test_classes.py index 52fd2b80c1..6be8b861d2 100644 --- a/zerver/lib/test_classes.py +++ b/zerver/lib/test_classes.py @@ -4,7 +4,6 @@ import re import shutil import subprocess import tempfile -import urllib from contextlib import contextmanager from datetime import timedelta from typing import ( @@ -25,6 +24,7 @@ from typing import ( cast, ) from unittest import TestResult, mock, skipUnless +from urllib.parse import parse_qs, quote, urlencode import lxml.html import orjson @@ -278,7 +278,7 @@ Output: url_split = url.split("?") data = {} if len(url_split) == 2: - data = urllib.parse.parse_qs(url_split[1]) + data = parse_qs(url_split[1]) url = url_split[0] url = url.replace("/json/", "/").replace("/api/v1/", "/") return (url, data) @@ -342,7 +342,7 @@ Output: """ We need to urlencode, since Django's function won't do it for us. """ - encoded = urllib.parse.urlencode(info) + encoded = urlencode(info) extra["content_type"] = "application/x-www-form-urlencoded" django_client = self.client # see WRAPPER_COMMENT self.set_http_headers(extra, skip_user_agent) @@ -434,7 +434,7 @@ Output: headers: Optional[Mapping[str, Any]] = None, **extra: str, ) -> "TestHttpResponse": - encoded = urllib.parse.urlencode(info) + encoded = urlencode(info) extra["content_type"] = "application/x-www-form-urlencoded" django_client = self.client # see WRAPPER_COMMENT self.set_http_headers(extra, skip_user_agent) @@ -477,7 +477,7 @@ Output: intentionally_undocumented: bool = False, **extra: str, ) -> "TestHttpResponse": - encoded = urllib.parse.urlencode(info) + encoded = urlencode(info) extra["content_type"] = "application/x-www-form-urlencoded" django_client = self.client # see WRAPPER_COMMENT self.set_http_headers(extra, skip_user_agent) @@ -807,9 +807,7 @@ Output: def register(self, email: str, password: str, subdomain: str = DEFAULT_SUBDOMAIN) -> None: response = self.client_post("/accounts/home/", {"email": email}, subdomain=subdomain) self.assertEqual(response.status_code, 302) - self.assertEqual( - response["Location"], f"/accounts/send_confirm/?email={urllib.parse.quote(email)}" - ) + self.assertEqual(response["Location"], f"/accounts/send_confirm/?email={quote(email)}") response = self.submit_reg_form_for_user(email, password, subdomain=subdomain) self.assertEqual(response.status_code, 302) self.assertEqual(response["Location"], f"http://{Realm.host_for_subdomain(subdomain)}/") @@ -2408,7 +2406,7 @@ class BouncerTestCase(ZulipTestCase): kwargs = dict(content_type="application/json") else: assert isinstance(request.body, str) or request.body is None - params: Dict[str, List[str]] = urllib.parse.parse_qs(request.body) + params: Dict[str, List[str]] = parse_qs(request.body) # In Python 3, the values of the dict from `parse_qs` are # in a list, because there might be multiple values. # But since we are sending values with no same keys, hence diff --git a/zerver/lib/upload/__init__.py b/zerver/lib/upload/__init__.py index 46b1b99883..d8a03a7fa2 100644 --- a/zerver/lib/upload/__init__.py +++ b/zerver/lib/upload/__init__.py @@ -1,10 +1,9 @@ import io import logging -import urllib from datetime import datetime from mimetypes import guess_type from typing import IO, Any, BinaryIO, Callable, Iterator, List, Optional, Tuple, Union -from urllib.parse import urljoin +from urllib.parse import unquote, urljoin from django.conf import settings from django.core.files.uploadedfile import UploadedFile @@ -47,7 +46,7 @@ def get_file_info(user_file: UploadedFile) -> Tuple[str, str]: # different content-type from the filename. content_type = "application/octet-stream" - uploaded_file_name = urllib.parse.unquote(uploaded_file_name) + uploaded_file_name = unquote(uploaded_file_name) return uploaded_file_name, content_type diff --git a/zerver/lib/upload/s3.py b/zerver/lib/upload/s3.py index 9d333d54f8..a9266ca691 100644 --- a/zerver/lib/upload/s3.py +++ b/zerver/lib/upload/s3.py @@ -1,10 +1,10 @@ import logging import os import secrets -import urllib from datetime import datetime from mimetypes import guess_type from typing import IO, Any, BinaryIO, Callable, Iterator, List, Literal, Optional, Tuple +from urllib.parse import urljoin, urlsplit, urlunsplit import boto3 import botocore @@ -188,10 +188,10 @@ class S3UploadBackend(ZulipUploadBackend): }, ExpiresIn=0, ) - split_url = urllib.parse.urlsplit(foo_url) + split_url = urlsplit(foo_url) assert split_url.path.endswith(f"/{DUMMY_KEY}") - return urllib.parse.urlunsplit( + return urlunsplit( (split_url.scheme, split_url.netloc, split_url.path[: -len(DUMMY_KEY)], "", "") ) @@ -204,7 +204,7 @@ class S3UploadBackend(ZulipUploadBackend): key: str, ) -> str: assert not key.startswith("/") - return urllib.parse.urljoin(self.public_upload_url_base, key) + return urljoin(self.public_upload_url_base, key) @override def generate_message_upload_path(self, realm_id: str, uploaded_file_name: str) -> str: diff --git a/zerver/tests/test_auth_backends.py b/zerver/tests/test_auth_backends.py index 95b0e50e8f..251f34943c 100644 --- a/zerver/tests/test_auth_backends.py +++ b/zerver/tests/test_auth_backends.py @@ -5,7 +5,6 @@ import os import re import secrets import time -import urllib from abc import ABC, abstractmethod from contextlib import contextmanager from datetime import timedelta @@ -25,7 +24,7 @@ from typing import ( Type, ) from unittest import mock -from urllib.parse import urlencode +from urllib.parse import parse_qs, urlencode, urlparse import jwt import ldap @@ -978,8 +977,8 @@ class SocialAuthBase(DesktopFlowTestingLib, ZulipTestCase, ABC): headers: Any, **extra_data: Any, ) -> "TestHttpResponse": - parsed_url = urllib.parse.urlparse(result["Location"]) - csrf_state = urllib.parse.parse_qs(parsed_url.query)["state"] + parsed_url = urlparse(result["Location"]) + csrf_state = parse_qs(parsed_url.query)["state"] result = self.client_get(self.AUTH_FINISH_URL, dict(state=csrf_state), **headers) return result @@ -1158,7 +1157,7 @@ class SocialAuthBase(DesktopFlowTestingLib, ZulipTestCase, ABC): self.assertEqual(data["subdomain"], "zulip") self.assertEqual(data["redirect_to"], "/user_uploads/image") self.assertEqual(result.status_code, 302) - parsed_url = urllib.parse.urlparse(result["Location"]) + parsed_url = urlparse(result["Location"]) url = f"{parsed_url.scheme}://{parsed_url.netloc}{parsed_url.path}" self.assertTrue(url.startswith("http://zulip.testserver/accounts/login/subdomain/")) @@ -1182,7 +1181,7 @@ class SocialAuthBase(DesktopFlowTestingLib, ZulipTestCase, ABC): self.assertEqual(data["subdomain"], "zulip") self.assertEqual(data["redirect_to"], "/user_uploads/image") self.assertEqual(result.status_code, 302) - parsed_url = urllib.parse.urlparse(result["Location"]) + parsed_url = urlparse(result["Location"]) url = f"{parsed_url.scheme}://{parsed_url.netloc}{parsed_url.path}" self.assertTrue(url.startswith("http://zulip.testserver/accounts/login/subdomain/")) @@ -1308,8 +1307,8 @@ class SocialAuthBase(DesktopFlowTestingLib, ZulipTestCase, ABC): ) self.assertEqual(result.status_code, 302) redirect_url = result["Location"] - parsed_url = urllib.parse.urlparse(redirect_url) - query_params = urllib.parse.parse_qs(parsed_url.query) + parsed_url = urlparse(redirect_url) + query_params = parse_qs(parsed_url.query) self.assertEqual(parsed_url.scheme, "zulip") self.assertEqual(query_params["realm"], ["http://zulip.testserver"]) self.assertEqual(query_params["email"], [hamlet.delivery_email]) @@ -1404,7 +1403,7 @@ class SocialAuthBase(DesktopFlowTestingLib, ZulipTestCase, ABC): self.assertEqual(data["full_name"], self.example_user("hamlet").full_name) self.assertEqual(data["subdomain"], "zulip") self.assertEqual(result.status_code, 302) - parsed_url = urllib.parse.urlparse(result["Location"]) + parsed_url = urlparse(result["Location"]) url = f"{parsed_url.scheme}://{parsed_url.netloc}{parsed_url.path}" self.assertTrue(url.startswith("http://zulip.testserver/accounts/login/subdomain/")) hamlet = self.example_user("hamlet") @@ -1430,7 +1429,7 @@ class SocialAuthBase(DesktopFlowTestingLib, ZulipTestCase, ABC): self.assertEqual(data["full_name"], name) self.assertEqual(data["subdomain"], "zulip") self.assertEqual(result.status_code, 302) - parsed_url = urllib.parse.urlparse(result["Location"]) + parsed_url = urlparse(result["Location"]) url = f"{parsed_url.scheme}://{parsed_url.netloc}{parsed_url.path}" self.assertTrue(url.startswith("http://zulip.testserver/accounts/login/subdomain/")) @@ -1473,8 +1472,8 @@ class SocialAuthBase(DesktopFlowTestingLib, ZulipTestCase, ABC): if mobile_flow_otp: self.assertEqual(result.status_code, 302) redirect_url = result["Location"] - parsed_url = urllib.parse.urlparse(redirect_url) - query_params = urllib.parse.parse_qs(parsed_url.query) + parsed_url = urlparse(redirect_url) + query_params = parse_qs(parsed_url.query) self.assertEqual(parsed_url.scheme, "zulip") self.assertEqual(query_params["realm"], ["http://zulip.testserver"]) self.assertEqual(query_params["email"], [email]) @@ -1716,7 +1715,7 @@ class SocialAuthBase(DesktopFlowTestingLib, ZulipTestCase, ABC): self.assertEqual(data["full_name"], name) self.assertEqual(data["subdomain"], "zulip") self.assertEqual(result.status_code, 302) - parsed_url = urllib.parse.urlparse(result["Location"]) + parsed_url = urlparse(result["Location"]) url = f"{parsed_url.scheme}://{parsed_url.netloc}{parsed_url.path}" self.assertTrue(url.startswith("http://zulip.testserver/accounts/login/subdomain/")) @@ -1740,7 +1739,7 @@ class SocialAuthBase(DesktopFlowTestingLib, ZulipTestCase, ABC): self.assertEqual(data["full_name"], name) self.assertEqual(data["subdomain"], "zulip") self.assertEqual(result.status_code, 302) - parsed_url = urllib.parse.urlparse(result["Location"]) + parsed_url = urlparse(result["Location"]) url = f"{parsed_url.scheme}://{parsed_url.netloc}{parsed_url.path}" self.assertTrue(url.startswith("http://zulip.testserver/accounts/login/subdomain/")) @@ -1996,8 +1995,8 @@ class SAMLAuthBackendTest(SocialAuthBase): assert "samlrequest" in result["Location"].lower() self.client.cookies = result.cookies - parsed_url = urllib.parse.urlparse(result["Location"]) - relay_state = urllib.parse.parse_qs(parsed_url.query)["RelayState"][0] + parsed_url = urlparse(result["Location"]) + relay_state = parse_qs(parsed_url.query)["RelayState"][0] # Make sure params are getting encoded into RelayState: data = SAMLAuthBackend.get_data_from_redis(orjson.loads(relay_state)["state_token"]) assert data is not None @@ -2149,7 +2148,7 @@ class SAMLAuthBackendTest(SocialAuthBase): # Verify the redirect has the correct form - a LogoutRequest for hamlet # is delivered to the IdP in the SAMLRequest param. - query_dict = urllib.parse.parse_qs(urllib.parse.urlparse(result["Location"]).query) + query_dict = parse_qs(urlparse(result["Location"]).query) saml_request_encoded = query_dict["SAMLRequest"][0] saml_request = OneLogin_Saml2_Utils.decode_base64_and_inflate(saml_request_encoded).decode() self.assertIn(" "TestHttpResponse": - parsed_url = urllib.parse.urlparse(result["Location"]) - state = urllib.parse.parse_qs(parsed_url.query)["state"] + parsed_url = urlparse(result["Location"]) + state = parse_qs(parsed_url.query)["state"] user_param = json.dumps(account_data_dict) self.client.session.flush() result = self.client_post( @@ -3924,8 +3923,8 @@ class GitHubAuthBackendTest(SocialAuthBase): expect_noreply_email_allowed: bool = False, **extra_data: Any, ) -> "TestHttpResponse": - parsed_url = urllib.parse.urlparse(result["Location"]) - csrf_state = urllib.parse.parse_qs(parsed_url.query)["state"] + parsed_url = urlparse(result["Location"]) + csrf_state = parse_qs(parsed_url.query)["state"] result = self.client_get(self.AUTH_FINISH_URL, dict(state=csrf_state), **headers) if expect_choose_email_screen: @@ -4121,7 +4120,7 @@ class GitHubAuthBackendTest(SocialAuthBase): self.assertEqual(data["subdomain"], "zulip") self.assertEqual(data["redirect_to"], "/user_uploads/image") self.assertEqual(result.status_code, 302) - parsed_url = urllib.parse.urlparse(result["Location"]) + parsed_url = urlparse(result["Location"]) url = f"{parsed_url.scheme}://{parsed_url.netloc}{parsed_url.path}" self.assertTrue(url.startswith("http://zulip.testserver/accounts/login/subdomain/")) @@ -4146,7 +4145,7 @@ class GitHubAuthBackendTest(SocialAuthBase): self.assertEqual(data["subdomain"], "zulip") self.assertEqual(data["redirect_to"], "/user_uploads/image") self.assertEqual(result.status_code, 302) - parsed_url = urllib.parse.urlparse(result["Location"]) + parsed_url = urlparse(result["Location"]) url = f"{parsed_url.scheme}://{parsed_url.netloc}{parsed_url.path}" self.assertTrue(url.startswith("http://zulip.testserver/accounts/login/subdomain/")) @@ -4175,7 +4174,7 @@ class GitHubAuthBackendTest(SocialAuthBase): self.assertEqual(data["subdomain"], "zulip") self.assertEqual(data["redirect_to"], "/user_uploads/image") self.assertEqual(result.status_code, 302) - parsed_url = urllib.parse.urlparse(result["Location"]) + parsed_url = urlparse(result["Location"]) url = f"{parsed_url.scheme}://{parsed_url.netloc}{parsed_url.path}" self.assertTrue(url.startswith("http://zulip.testserver/accounts/login/subdomain/")) @@ -4204,7 +4203,7 @@ class GitHubAuthBackendTest(SocialAuthBase): self.assertEqual(data["subdomain"], "zulip") self.assertEqual(data["redirect_to"], "/user_uploads/image") self.assertEqual(result.status_code, 302) - parsed_url = urllib.parse.urlparse(result["Location"]) + parsed_url = urlparse(result["Location"]) url = f"{parsed_url.scheme}://{parsed_url.netloc}{parsed_url.path}" self.assertTrue(url.startswith("http://zulip.testserver/accounts/login/subdomain/")) @@ -4265,7 +4264,7 @@ class GitHubAuthBackendTest(SocialAuthBase): self.assertEqual(data["subdomain"], "zulip") self.assertEqual(data["redirect_to"], "/user_uploads/image") self.assertEqual(result.status_code, 302) - parsed_url = urllib.parse.urlparse(result["Location"]) + parsed_url = urlparse(result["Location"]) url = f"{parsed_url.scheme}://{parsed_url.netloc}{parsed_url.path}" self.assertTrue(url.startswith("http://zulip.testserver/accounts/login/subdomain/")) @@ -4348,7 +4347,7 @@ class GitHubAuthBackendTest(SocialAuthBase): self.assertEqual(data["full_name"], account_data_dict["name"]) self.assertEqual(data["subdomain"], "zulip") self.assertEqual(result.status_code, 302) - parsed_url = urllib.parse.urlparse(result["Location"]) + parsed_url = urlparse(result["Location"]) url = f"{parsed_url.scheme}://{parsed_url.netloc}{parsed_url.path}" self.assertTrue(url.startswith("http://zulip.testserver/accounts/login/subdomain/")) @@ -4487,8 +4486,8 @@ class GoogleAuthBackendTest(SocialAuthBase): self.assertEqual(result.status_code, 302) redirect_url = result["Location"] - parsed_url = urllib.parse.urlparse(redirect_url) - query_params = urllib.parse.parse_qs(parsed_url.query) + parsed_url = urlparse(redirect_url) + query_params = parse_qs(parsed_url.query) self.assertEqual(parsed_url.scheme, "zulip") self.assertEqual(query_params["realm"], ["http://zulip-mobile.testserver"]) self.assertEqual(query_params["email"], [self.example_email("hamlet")]) @@ -4532,8 +4531,8 @@ class GoogleAuthBackendTest(SocialAuthBase): ) self.assertEqual(result.status_code, 302) redirect_url = result["Location"] - parsed_url = urllib.parse.urlparse(redirect_url) - query_params = urllib.parse.parse_qs(parsed_url.query) + parsed_url = urlparse(redirect_url) + query_params = parse_qs(parsed_url.query) self.assertEqual(parsed_url.scheme, "zulip") self.assertEqual(query_params["realm"], ["http://zulip.testserver"]) self.assertEqual(query_params["email"], [self.example_email("hamlet")]) @@ -5530,7 +5529,7 @@ class TestZulipRemoteUserBackend(DesktopFlowTestingLib, ZulipTestCase): self.assertEqual(result.status_code, 302) url = result["Location"] - parsed_url = urllib.parse.urlparse(url) + parsed_url = urlparse(url) self.assertEqual(parsed_url.path, "/accounts/login/sso/") self.assertEqual(parsed_url.query, "param1=value1¶ms=value2") @@ -5674,8 +5673,8 @@ class TestZulipRemoteUserBackend(DesktopFlowTestingLib, ZulipTestCase): ) self.assertEqual(result.status_code, 302) redirect_url = result["Location"] - parsed_url = urllib.parse.urlparse(redirect_url) - query_params = urllib.parse.parse_qs(parsed_url.query) + parsed_url = urlparse(redirect_url) + query_params = parse_qs(parsed_url.query) self.assertEqual(parsed_url.scheme, "zulip") self.assertEqual(query_params["realm"], ["http://zulip.testserver"]) self.assertEqual(query_params["email"], [self.example_email("hamlet")]) @@ -5723,8 +5722,8 @@ class TestZulipRemoteUserBackend(DesktopFlowTestingLib, ZulipTestCase): ) self.assertEqual(result.status_code, 302) redirect_url = result["Location"] - parsed_url = urllib.parse.urlparse(redirect_url) - query_params = urllib.parse.parse_qs(parsed_url.query) + parsed_url = urlparse(redirect_url) + query_params = parse_qs(parsed_url.query) self.assertEqual(parsed_url.scheme, "zulip") self.assertEqual(query_params["realm"], ["http://zulip.testserver"]) self.assertEqual(query_params["email"], [self.example_email("hamlet")]) diff --git a/zerver/tests/test_home.py b/zerver/tests/test_home.py index 5f6e25d579..f6d6e6ec78 100644 --- a/zerver/tests/test_home.py +++ b/zerver/tests/test_home.py @@ -1,8 +1,8 @@ import calendar -import urllib from datetime import timedelta, timezone from typing import TYPE_CHECKING, Any, Dict from unittest.mock import patch +from urllib.parse import urlparse import orjson import time_machine @@ -1011,7 +1011,7 @@ class HomeTest(ZulipTestCase): self.assertTrue(result["Location"].endswith("/desktop_home/")) result = self.client_get("/desktop_home/") self.assertEqual(result.status_code, 302) - path = urllib.parse.urlparse(result["Location"]).path + path = urlparse(result["Location"]).path self.assertEqual(path, "/") @override_settings(SERVER_UPGRADE_NAG_DEADLINE_DAYS=365) diff --git a/zerver/tests/test_invite.py b/zerver/tests/test_invite.py index eb0197ae92..d2f146868d 100644 --- a/zerver/tests/test_invite.py +++ b/zerver/tests/test_invite.py @@ -1,9 +1,8 @@ import re -import urllib from datetime import datetime, timedelta from typing import TYPE_CHECKING, List, Optional, Sequence, Union from unittest.mock import patch -from urllib.parse import urlencode +from urllib.parse import quote, urlencode import orjson import time_machine @@ -2294,9 +2293,7 @@ class MultiuseInviteTest(ZulipTestCase): result = self.client_post(invite_link, {"email": email}) self.assertEqual(result.status_code, 302) self.assertTrue( - result["Location"].endswith( - f"/accounts/send_confirm/?email={urllib.parse.quote(email)}" - ) + result["Location"].endswith(f"/accounts/send_confirm/?email={quote(email)}") ) result = self.client_get(result["Location"]) self.assert_in_response("check your email", result) diff --git a/zerver/tests/test_management_commands.py b/zerver/tests/test_management_commands.py index 4aad5a9e13..26bb8801b0 100644 --- a/zerver/tests/test_management_commands.py +++ b/zerver/tests/test_management_commands.py @@ -1,10 +1,10 @@ import os import re -import urllib from datetime import timedelta from typing import Any, Dict, List, Optional from unittest import mock, skipUnless from unittest.mock import MagicMock, call, patch +from urllib.parse import quote, quote_plus from django.apps import apps from django.conf import settings @@ -344,7 +344,7 @@ class TestGenerateRealmCreationLink(ZulipTestCase): ) self.assertEqual(result.status_code, 302) self.assertEqual( - f"/accounts/new/send_confirm/?email={urllib.parse.quote(email)}&realm_name={urllib.parse.quote_plus(realm_name)}&realm_type=10&realm_default_language=en&realm_subdomain={string_id}", + f"/accounts/new/send_confirm/?email={quote(email)}&realm_name={quote_plus(realm_name)}&realm_type=10&realm_default_language=en&realm_subdomain={string_id}", result["Location"], ) result = self.client_get(result["Location"]) diff --git a/zerver/tests/test_signup.py b/zerver/tests/test_signup.py index 61f56da3f4..4b0c531e42 100644 --- a/zerver/tests/test_signup.py +++ b/zerver/tests/test_signup.py @@ -1,10 +1,9 @@ import re import time -import urllib from datetime import timedelta from typing import TYPE_CHECKING, Any, Dict, Optional, Sequence, Union from unittest.mock import MagicMock, patch -from urllib.parse import urlencode +from urllib.parse import quote, quote_plus, urlencode, urlparse import orjson from django.conf import settings @@ -1096,7 +1095,7 @@ class EmailUnsubscribeTests(ZulipTestCase): # An unknown message type "fake" produces an error. user_profile = self.example_user("hamlet") unsubscribe_link = one_click_unsubscribe_link(user_profile, "fake") - result = self.client_get(urllib.parse.urlparse(unsubscribe_link).path) + result = self.client_get(urlparse(unsubscribe_link).path) self.assert_in_response("Unknown email unsubscribe request", result) def test_message_notification_emails_unsubscribe(self) -> None: @@ -1110,7 +1109,7 @@ class EmailUnsubscribeTests(ZulipTestCase): user_profile.save() unsubscribe_link = one_click_unsubscribe_link(user_profile, "missed_messages") - result = self.client_get(urllib.parse.urlparse(unsubscribe_link).path) + result = self.client_get(urlparse(unsubscribe_link).path) self.assertEqual(result.status_code, 200) @@ -1129,7 +1128,7 @@ class EmailUnsubscribeTests(ZulipTestCase): # Simulate unsubscribing from the welcome e-mails. unsubscribe_link = one_click_unsubscribe_link(user_profile, "welcome") - result = self.client_get(urllib.parse.urlparse(unsubscribe_link).path) + result = self.client_get(urlparse(unsubscribe_link).path) # The welcome email jobs are no longer scheduled. self.assertEqual(result.status_code, 200) @@ -1167,7 +1166,7 @@ class EmailUnsubscribeTests(ZulipTestCase): # Simulate unsubscribing from digest e-mails. unsubscribe_link = one_click_unsubscribe_link(user_profile, "digest") - result = self.client_get(urllib.parse.urlparse(unsubscribe_link).path) + result = self.client_get(urlparse(unsubscribe_link).path) # The setting is toggled off, and scheduled jobs have been removed. self.assertEqual(result.status_code, 200) @@ -1188,7 +1187,7 @@ class EmailUnsubscribeTests(ZulipTestCase): user_profile.save() unsubscribe_link = one_click_unsubscribe_link(user_profile, "login") - result = self.client_get(urllib.parse.urlparse(unsubscribe_link).path) + result = self.client_get(urlparse(unsubscribe_link).path) self.assertEqual(result.status_code, 200) @@ -1205,7 +1204,7 @@ class EmailUnsubscribeTests(ZulipTestCase): # Simulate unsubscribing from marketing e-mails. unsubscribe_link = one_click_unsubscribe_link(user_profile, "marketing") - result = self.client_get(urllib.parse.urlparse(unsubscribe_link).path) + result = self.client_get(urlparse(unsubscribe_link).path) self.assertEqual(result.status_code, 200) # Circumvent user_profile caching. @@ -1224,9 +1223,7 @@ class EmailUnsubscribeTests(ZulipTestCase): # Simulate unsubscribing from marketing e-mails. unsubscribe_link = one_click_unsubscribe_link(user_profile, "marketing") client = Client(enforce_csrf_checks=True) - result = client.post( - urllib.parse.urlparse(unsubscribe_link).path, {"List-Unsubscribe": "One-Click"} - ) + result = client.post(urlparse(unsubscribe_link).path, {"List-Unsubscribe": "One-Click"}) self.assertEqual(result.status_code, 200) # Circumvent user_profile caching. @@ -1255,7 +1252,7 @@ class RealmCreationTest(ZulipTestCase): self.assertEqual(result.status_code, 302) self.assertTrue( result["Location"].endswith( - f"/accounts/new/send_confirm/?email={urllib.parse.quote(email)}&realm_name={urllib.parse.quote_plus(org_name)}&realm_type=10&realm_default_language=en&realm_subdomain={string_id}" + f"/accounts/new/send_confirm/?email={quote(email)}&realm_name={quote_plus(org_name)}&realm_type=10&realm_default_language=en&realm_subdomain={string_id}" ) ) result = self.client_get(result["Location"]) @@ -1398,7 +1395,7 @@ class RealmCreationTest(ZulipTestCase): self.assertEqual(result.status_code, 302) self.assertTrue( result["Location"].endswith( - f"/accounts/new/send_confirm/?email={urllib.parse.quote(email)}&realm_name={urllib.parse.quote_plus(realm_name)}&realm_type=10&realm_default_language=en&realm_subdomain={string_id}" + f"/accounts/new/send_confirm/?email={quote(email)}&realm_name={quote_plus(realm_name)}&realm_type=10&realm_default_language=en&realm_subdomain={string_id}" ) ) result = self.client_get(result["Location"]) @@ -1446,7 +1443,7 @@ class RealmCreationTest(ZulipTestCase): self.assertEqual(result.status_code, 302) self.assertTrue( result["Location"].endswith( - f"/accounts/new/send_confirm/?email={urllib.parse.quote(email)}&realm_name={urllib.parse.quote_plus(realm_name)}&realm_type=10&realm_default_language=en&realm_subdomain={string_id}" + f"/accounts/new/send_confirm/?email={quote(email)}&realm_name={quote_plus(realm_name)}&realm_type=10&realm_default_language=en&realm_subdomain={string_id}" ) ) result = self.client_get(result["Location"]) @@ -1495,7 +1492,7 @@ class RealmCreationTest(ZulipTestCase): self.assertEqual(result.status_code, 302) self.assertTrue( result["Location"].endswith( - f"/accounts/new/send_confirm/?email={urllib.parse.quote(email)}&realm_name={urllib.parse.quote_plus(realm_name)}&realm_type=10&realm_default_language=en&realm_subdomain={string_id}" + f"/accounts/new/send_confirm/?email={quote(email)}&realm_name={quote_plus(realm_name)}&realm_type=10&realm_default_language=en&realm_subdomain={string_id}" ) ) result = self.client_get(result["Location"]) @@ -1555,7 +1552,7 @@ class RealmCreationTest(ZulipTestCase): self.assertEqual(result.status_code, 302) self.assertTrue( result["Location"].endswith( - f"/accounts/new/send_confirm/?email={urllib.parse.quote(email)}&realm_name={urllib.parse.quote_plus(realm_name)}&realm_type=10&realm_default_language=en&realm_subdomain={string_id}" + f"/accounts/new/send_confirm/?email={quote(email)}&realm_name={quote_plus(realm_name)}&realm_type=10&realm_default_language=en&realm_subdomain={string_id}" ) ) result = self.client_get(result["Location"]) @@ -1600,7 +1597,7 @@ class RealmCreationTest(ZulipTestCase): self.assertEqual(result.status_code, 302) self.assertTrue( result["Location"].endswith( - f"/accounts/new/send_confirm/?email={urllib.parse.quote(email)}&realm_name={urllib.parse.quote_plus(realm_name)}&realm_type=10&realm_default_language=en&realm_subdomain={string_id}" + f"/accounts/new/send_confirm/?email={quote(email)}&realm_name={quote_plus(realm_name)}&realm_type=10&realm_default_language=en&realm_subdomain={string_id}" ) ) result = self.client_get(result["Location"]) @@ -1651,7 +1648,7 @@ class RealmCreationTest(ZulipTestCase): self.assertEqual(result.status_code, 302) self.assertTrue( result["Location"].endswith( - f"/accounts/new/send_confirm/?email={urllib.parse.quote(email)}&realm_name={urllib.parse.quote_plus(realm_name)}&realm_type=35&realm_default_language=en&realm_subdomain={string_id}" + f"/accounts/new/send_confirm/?email={quote(email)}&realm_name={quote_plus(realm_name)}&realm_type=35&realm_default_language=en&realm_subdomain={string_id}" ) ) result = self.client_get(result["Location"]) @@ -1708,7 +1705,7 @@ class RealmCreationTest(ZulipTestCase): self.assertEqual(result.status_code, 302) self.assertTrue( result["Location"].endswith( - f"/accounts/new/send_confirm/?email={urllib.parse.quote(email)}&realm_name={urllib.parse.quote_plus(realm_name)}&realm_type=10&realm_default_language={realm_language}&realm_subdomain={string_id}" + f"/accounts/new/send_confirm/?email={quote(email)}&realm_name={quote_plus(realm_name)}&realm_type=10&realm_default_language={realm_language}&realm_subdomain={string_id}" ) ) result = self.client_get(result["Location"]) @@ -1774,7 +1771,7 @@ class RealmCreationTest(ZulipTestCase): self.assertEqual(result.status_code, 302) self.assertTrue( result["Location"].endswith( - f"/accounts/new/send_confirm/?email={urllib.parse.quote(email)}&realm_name={urllib.parse.quote_plus(realm_name)}&realm_type=10&realm_default_language=en&realm_subdomain={string_id}" + f"/accounts/new/send_confirm/?email={quote(email)}&realm_name={quote_plus(realm_name)}&realm_type=10&realm_default_language=en&realm_subdomain={string_id}" ) ) result = self.client_get(result["Location"]) @@ -1830,7 +1827,7 @@ class RealmCreationTest(ZulipTestCase): self.assertEqual(result.status_code, 302) self.assertTrue( result["Location"].endswith( - f"/accounts/new/send_confirm/?email={urllib.parse.quote(email)}&realm_name={urllib.parse.quote_plus(first_realm_name)}&realm_type=10&realm_default_language=en&realm_subdomain={first_string_id}" + f"/accounts/new/send_confirm/?email={quote(email)}&realm_name={quote_plus(first_realm_name)}&realm_type=10&realm_default_language=en&realm_subdomain={first_string_id}" ) ) result = self.client_get(result["Location"]) @@ -1846,7 +1843,7 @@ class RealmCreationTest(ZulipTestCase): self.assertEqual(result.status_code, 302) self.assertTrue( result["Location"].endswith( - f"/accounts/new/send_confirm/?email={urllib.parse.quote(email)}&realm_name={urllib.parse.quote_plus(second_realm_name)}&realm_type=10&realm_default_language=en&realm_subdomain={second_string_id}" + f"/accounts/new/send_confirm/?email={quote(email)}&realm_name={quote_plus(second_realm_name)}&realm_type=10&realm_default_language=en&realm_subdomain={second_string_id}" ) ) result = self.client_get(result["Location"]) @@ -2118,9 +2115,7 @@ class UserSignUpTest(ZulipTestCase): result = self.client_post("/accounts/home/", {"email": email}, **client_kwargs) self.assertEqual(result.status_code, 302) self.assertTrue( - result["Location"].endswith( - f"/accounts/send_confirm/?email={urllib.parse.quote(email)}" - ) + result["Location"].endswith(f"/accounts/send_confirm/?email={quote(email)}") ) result = self.client_get(result["Location"], **client_kwargs) self.assert_in_response("check your email", result) @@ -2261,9 +2256,7 @@ class UserSignUpTest(ZulipTestCase): result = self.client_post("/accounts/home/", {"email": email}) self.assertEqual(result.status_code, 302) self.assertTrue( - result["Location"].endswith( - f"/accounts/send_confirm/?email={urllib.parse.quote(email)}" - ) + result["Location"].endswith(f"/accounts/send_confirm/?email={quote(email)}") ) result = self.client_get(result["Location"]) self.assert_in_response("check your email", result) @@ -2296,9 +2289,7 @@ class UserSignUpTest(ZulipTestCase): result = self.client_post("/accounts/home/", {"email": email}) self.assertEqual(result.status_code, 302) self.assertTrue( - result["Location"].endswith( - f"/accounts/send_confirm/?email={urllib.parse.quote(email)}" - ) + result["Location"].endswith(f"/accounts/send_confirm/?email={quote(email)}") ) result = self.client_get(result["Location"]) self.assert_in_response("check your email", result) @@ -2334,9 +2325,7 @@ class UserSignUpTest(ZulipTestCase): result = self.client_post("/accounts/home/", {"email": email}) self.assertEqual(result.status_code, 302) self.assertTrue( - result["Location"].endswith( - f"/accounts/send_confirm/?email={urllib.parse.quote(email)}" - ) + result["Location"].endswith(f"/accounts/send_confirm/?email={quote(email)}") ) result = self.client_get(result["Location"]) self.assert_in_response("check your email", result) @@ -2367,9 +2356,7 @@ class UserSignUpTest(ZulipTestCase): result = self.client_post("/accounts/home/", {"email": email}) self.assertEqual(result.status_code, 302) self.assertTrue( - result["Location"].endswith( - f"/accounts/send_confirm/?email={urllib.parse.quote(email)}" - ) + result["Location"].endswith(f"/accounts/send_confirm/?email={quote(email)}") ) result = self.client_get(result["Location"]) self.assert_in_response("check your email", result) @@ -2472,9 +2459,7 @@ class UserSignUpTest(ZulipTestCase): result = self.client_post("/accounts/home/", {"email": email}) self.assertEqual(result.status_code, 302) self.assertTrue( - result["Location"].endswith( - f"/accounts/send_confirm/?email={urllib.parse.quote(email)}" - ) + result["Location"].endswith(f"/accounts/send_confirm/?email={quote(email)}") ) result = self.client_get(result["Location"]) self.assert_in_response("check your email", result) @@ -2521,7 +2506,7 @@ class UserSignUpTest(ZulipTestCase): self.assertEqual(result.status_code, 302) self.assertTrue( result["Location"].endswith( - f"/accounts/login/?email={urllib.parse.quote(email)}&already_registered=1" + f"/accounts/login/?email={quote(email)}&already_registered=1" ) ) @@ -2790,9 +2775,7 @@ class UserSignUpTest(ZulipTestCase): result = self.client_post("/accounts/home/", {"email": email}) self.assertEqual(result.status_code, 302) self.assertTrue( - result["Location"].endswith( - f"/accounts/send_confirm/?email={urllib.parse.quote(email)}" - ) + result["Location"].endswith(f"/accounts/send_confirm/?email={quote(email)}") ) result = self.client_get(result["Location"]) self.assert_in_response("check your email", result) @@ -2974,9 +2957,7 @@ class UserSignUpTest(ZulipTestCase): self.assertEqual(result.status_code, 302) self.assertTrue( - result["Location"].endswith( - f"/accounts/send_confirm/?email={urllib.parse.quote(email)}" - ) + result["Location"].endswith(f"/accounts/send_confirm/?email={quote(email)}") ) result = self.client_get(result["Location"]) self.assert_in_response("check your email", result) @@ -3062,9 +3043,7 @@ class UserSignUpTest(ZulipTestCase): self.assertEqual(result.status_code, 302) self.assertTrue( - result["Location"].endswith( - f"/accounts/send_confirm/?email={urllib.parse.quote(email)}" - ) + result["Location"].endswith(f"/accounts/send_confirm/?email={quote(email)}") ) result = self.client_get(result["Location"]) self.assert_in_response("check your email", result) @@ -3146,9 +3125,7 @@ class UserSignUpTest(ZulipTestCase): self.assertEqual(result.status_code, 302) self.assertTrue( - result["Location"].endswith( - f"/accounts/send_confirm/?email={urllib.parse.quote(email)}" - ) + result["Location"].endswith(f"/accounts/send_confirm/?email={quote(email)}") ) result = self.client_get(result["Location"]) self.assert_in_response("check your email", result) @@ -3223,9 +3200,7 @@ class UserSignUpTest(ZulipTestCase): self.assertEqual(result.status_code, 302) self.assertTrue( - result["Location"].endswith( - f"/accounts/send_confirm/?email={urllib.parse.quote(email)}" - ) + result["Location"].endswith(f"/accounts/send_confirm/?email={quote(email)}") ) result = self.client_get(result["Location"]) self.assert_in_response("check your email", result) @@ -3299,9 +3274,7 @@ class UserSignUpTest(ZulipTestCase): self.assertEqual(result.status_code, 302) self.assertTrue( - result["Location"].endswith( - f"/accounts/send_confirm/?email={urllib.parse.quote(email)}" - ) + result["Location"].endswith(f"/accounts/send_confirm/?email={quote(email)}") ) result = self.client_get(result["Location"]) self.assert_in_response("check your email", result) @@ -3449,9 +3422,7 @@ class UserSignUpTest(ZulipTestCase): self.assertEqual(result.status_code, 302) self.assertTrue( - result["Location"].endswith( - f"/accounts/send_confirm/?email={urllib.parse.quote(email)}" - ) + result["Location"].endswith(f"/accounts/send_confirm/?email={quote(email)}") ) result = self.client_get(result["Location"]) self.assert_in_response("check your email", result) @@ -3504,9 +3475,7 @@ class UserSignUpTest(ZulipTestCase): self.assertEqual(result.status_code, 302) self.assertTrue( - result["Location"].endswith( - f"/accounts/send_confirm/?email={urllib.parse.quote(email)}" - ) + result["Location"].endswith(f"/accounts/send_confirm/?email={quote(email)}") ) result = self.client_get(result["Location"]) self.assert_in_response("check your email", result) @@ -3630,9 +3599,7 @@ class UserSignUpTest(ZulipTestCase): self.assertEqual(result.status_code, 302) self.assertTrue( - result["Location"].endswith( - f"/accounts/send_confirm/?email={urllib.parse.quote(email)}" - ) + result["Location"].endswith(f"/accounts/send_confirm/?email={quote(email)}") ) result = self.client_get(result["Location"]) self.assert_in_response("check your email", result) @@ -3675,9 +3642,7 @@ class UserSignUpTest(ZulipTestCase): self.assertEqual(result.status_code, 302) self.assertTrue( - result["Location"].endswith( - f"/accounts/send_confirm/?email={urllib.parse.quote(email)}" - ) + result["Location"].endswith(f"/accounts/send_confirm/?email={quote(email)}") ) result = self.client_get(result["Location"]) self.assert_in_response("check your email", result) @@ -3837,9 +3802,7 @@ class UserSignUpTest(ZulipTestCase): self.assertEqual(result.status_code, 302) self.assertTrue( - result["Location"].endswith( - f"/accounts/send_confirm/?email={urllib.parse.quote(email)}" - ) + result["Location"].endswith(f"/accounts/send_confirm/?email={quote(email)}") ) result = self.client_get(result["Location"]) self.assert_in_response("check your email", result) @@ -3870,9 +3833,7 @@ class UserSignUpTest(ZulipTestCase): self.assertEqual(result.status_code, 302) self.assertTrue( - result["Location"].endswith( - f"/accounts/send_confirm/?email={urllib.parse.quote(email)}" - ) + result["Location"].endswith(f"/accounts/send_confirm/?email={quote(email)}") ) result = self.client_get(result["Location"]) self.assert_in_response("check your email", result) @@ -3936,9 +3897,7 @@ class UserSignUpTest(ZulipTestCase): self.assertEqual(result.status_code, 302) self.assertTrue( - result["Location"].endswith( - f"/accounts/send_confirm/?email={urllib.parse.quote(email)}" - ) + result["Location"].endswith(f"/accounts/send_confirm/?email={quote(email)}") ) result = self.client_get(result["Location"], subdomain="zephyr") self.assert_in_response("check your email", result) diff --git a/zerver/tests/test_tornado.py b/zerver/tests/test_tornado.py index d2b920582f..4b24f6dc7c 100644 --- a/zerver/tests/test_tornado.py +++ b/zerver/tests/test_tornado.py @@ -1,9 +1,9 @@ import asyncio import socket -import urllib.parse from functools import wraps from typing import Any, Awaitable, Callable, Dict, Optional, TypeVar from unittest import TestResult, mock +from urllib.parse import urlencode import orjson from asgiref.sync import async_to_sync, sync_to_async @@ -120,7 +120,7 @@ class EventsTestCase(TornadoWebTestCase): "last_event_id": -1, } - path = f"/json/events?{urllib.parse.urlencode(data)}" + path = f"/json/events?{urlencode(data)}" def process_events() -> None: users = [user_profile.id] diff --git a/zerver/tests/test_upload.py b/zerver/tests/test_upload.py index 403b5277f0..240129561a 100644 --- a/zerver/tests/test_upload.py +++ b/zerver/tests/test_upload.py @@ -2,10 +2,10 @@ import io import os import re import time -import urllib from io import StringIO from unittest import mock from unittest.mock import patch +from urllib.parse import quote import orjson from django.conf import settings @@ -572,7 +572,7 @@ class FileUploadTest(UploadSerializeMixin, ZulipTestCase): self.login("hamlet") for expected in ["Здравейте.txt", "test"]: fp = StringIO("bah!") - fp.name = urllib.parse.quote(expected) + fp.name = quote(expected) result = self.client_post("/json/user_uploads", {"f1": fp}) response_dict = self.assert_json_success(result) @@ -590,7 +590,7 @@ class FileUploadTest(UploadSerializeMixin, ZulipTestCase): ("**", "uploaded-file"), ]: fp = StringIO("bah!") - fp.name = urllib.parse.quote(uploaded_filename) + fp.name = quote(uploaded_filename) result = self.client_post("/json/user_uploads", {"f1": fp}) response_dict = self.assert_json_success(result) diff --git a/zerver/tests/test_upload_local.py b/zerver/tests/test_upload_local.py index c0d6de0bf8..bec96f2bd2 100644 --- a/zerver/tests/test_upload_local.py +++ b/zerver/tests/test_upload_local.py @@ -1,6 +1,5 @@ import os import re -import urllib from io import BytesIO, StringIO from urllib.parse import urlparse @@ -258,5 +257,5 @@ class LocalStorageTest(UploadSerializeMixin, ZulipTestCase): warn_log.output, ["WARNING:root:not_a_file does not exist. Its entry in the database will be removed."], ) - path_id = urllib.parse.urlparse(url).path + path_id = urlparse(url).path self.assertEqual(delete_export_tarball(path_id), path_id) diff --git a/zerver/tests/test_upload_s3.py b/zerver/tests/test_upload_s3.py index 359be18674..cd06bb4105 100644 --- a/zerver/tests/test_upload_s3.py +++ b/zerver/tests/test_upload_s3.py @@ -1,9 +1,9 @@ import io import os import re -import urllib from io import BytesIO, StringIO from unittest.mock import patch +from urllib.parse import urlparse import botocore.exceptions from django.conf import settings @@ -191,7 +191,7 @@ class S3Test(ZulipTestCase): # In development, this is just a redirect response = self.client_get(url) redirect_url = response["Location"] - path = urllib.parse.urlparse(redirect_url).path + path = urlparse(redirect_url).path assert path.startswith("/") key = path[len("/") :] self.assertEqual(b"zulip!", bucket.Object(key).get()["Body"].read()) @@ -200,7 +200,7 @@ class S3Test(ZulipTestCase): with self.settings(DEVELOPMENT=False): response = self.client_get(url) redirect_url = response["X-Accel-Redirect"] - path = urllib.parse.urlparse(redirect_url).path + path = urlparse(redirect_url).path assert path.startswith(prefix) key = path[len(prefix) :] self.assertEqual(b"zulip!", bucket.Object(key).get()["Body"].read()) @@ -210,7 +210,7 @@ class S3Test(ZulipTestCase): with self.settings(DEVELOPMENT=False): response = self.client_get(download_url) redirect_url = response["X-Accel-Redirect"] - path = urllib.parse.urlparse(redirect_url).path + path = urlparse(redirect_url).path assert path.startswith(prefix) key = path[len(prefix) :] self.assertEqual(b"zulip!", bucket.Object(key).get()["Body"].read()) @@ -230,7 +230,7 @@ class S3Test(ZulipTestCase): with self.settings(DEVELOPMENT=False): self.client_get(url_only_url) redirect_url = response["X-Accel-Redirect"] - path = urllib.parse.urlparse(redirect_url).path + path = urlparse(redirect_url).path assert path.startswith(prefix) key = path[len(prefix) :] self.assertEqual(b"zulip!", bucket.Object(key).get()["Body"].read()) @@ -532,5 +532,5 @@ class S3Test(ZulipTestCase): warn_log.output, ["WARNING:root:not_a_file does not exist. Its entry in the database will be removed."], ) - path_id = urllib.parse.urlparse(url).path + path_id = urlparse(url).path self.assertEqual(delete_export_tarball(path_id), path_id) diff --git a/zerver/tornado/handlers.py b/zerver/tornado/handlers.py index a2effd58b2..a285ac1b22 100644 --- a/zerver/tornado/handlers.py +++ b/zerver/tornado/handlers.py @@ -1,7 +1,7 @@ import logging -import urllib from contextlib import suppress from typing import Any, Dict, List, Optional +from urllib.parse import unquote import tornado.web from asgiref.sync import sync_to_async @@ -108,7 +108,7 @@ class AsyncDjangoHandler(tornado.web.RequestHandler): # HttpRequest object with the original Tornado request's HTTP # headers, parameters, etc. environ = fake_wsgi_container.environ(self.request) - environ["PATH_INFO"] = urllib.parse.unquote(environ["PATH_INFO"]) + environ["PATH_INFO"] = unquote(environ["PATH_INFO"]) # Django WSGIRequest setup code that should match logic from # Django's WSGIHandler.__call__ before the call to diff --git a/zerver/views/auth.py b/zerver/views/auth.py index 7696451746..5c447abeb5 100644 --- a/zerver/views/auth.py +++ b/zerver/views/auth.py @@ -1,9 +1,8 @@ import logging import secrets -import urllib from functools import wraps from typing import TYPE_CHECKING, Any, Callable, Dict, List, Mapping, Optional, Tuple, cast -from urllib.parse import urlencode +from urllib.parse import urlencode, urljoin import jwt import orjson @@ -115,7 +114,7 @@ def get_safe_redirect_to(url: str, redirect_host: str) -> str: # Mark as safe to prevent Pysa from surfacing false positives for # open redirects. In this branch, we have already checked that the URL # points to the specified 'redirect_host', or is relative. - return urllib.parse.urljoin(redirect_host, mark_sanitized(url)) + return urljoin(redirect_host, mark_sanitized(url)) else: return redirect_host @@ -478,7 +477,7 @@ def create_response_for_otp_flow( } # We can't use HttpResponseRedirect, since it only allows HTTP(S) URLs response = HttpResponse(status=302) - response["Location"] = append_url_query_string("zulip://login", urllib.parse.urlencode(params)) + response["Location"] = append_url_query_string("zulip://login", urlencode(params)) return response @@ -628,7 +627,7 @@ def oauth_redirect_to_root( params = {**params, **extra_url_params} - return redirect(append_url_query_string(main_site_url, urllib.parse.urlencode(params))) + return redirect(append_url_query_string(main_site_url, urlencode(params))) def handle_desktop_flow( diff --git a/zerver/views/development/email_log.py b/zerver/views/development/email_log.py index 72f757a061..4b4fe010cb 100644 --- a/zerver/views/development/email_log.py +++ b/zerver/views/development/email_log.py @@ -1,7 +1,7 @@ import os -import urllib from contextlib import suppress from typing import Optional +from urllib.parse import urlencode import orjson from django.conf import settings @@ -121,7 +121,7 @@ def generate_all_emails(request: HttpRequest) -> HttpResponse: # Verification for new email result = client.patch( "/json/settings", - urllib.parse.urlencode({"email": "hamlets-new@zulip.com"}), + urlencode({"email": "hamlets-new@zulip.com"}), content_type="application/x-www-form-urlencoded", HTTP_HOST=realm.host, ) diff --git a/zerver/views/registration.py b/zerver/views/registration.py index 02594b7f29..ff3436e204 100644 --- a/zerver/views/registration.py +++ b/zerver/views/registration.py @@ -1,5 +1,4 @@ import logging -import urllib from contextlib import suppress from typing import Any, Dict, Iterable, List, Optional, Tuple, Union from urllib.parse import urlencode, urljoin @@ -1109,7 +1108,7 @@ def find_account( # Note: Show all the emails in the result otherwise this # feature can be used to ascertain which email addresses # are associated with Zulip. - data = urllib.parse.urlencode({"emails": ",".join(emails)}) + data = urlencode({"emails": ",".join(emails)}) return redirect(append_url_query_string(url, data)) else: form = FindMyTeamForm() diff --git a/zerver/views/sentry.py b/zerver/views/sentry.py index 042e42dfdc..734e2688e7 100644 --- a/zerver/views/sentry.py +++ b/zerver/views/sentry.py @@ -1,7 +1,7 @@ import logging -import urllib from contextlib import suppress from typing import Type +from urllib.parse import urlparse import orjson from circuitbreaker import CircuitBreakerError, circuit @@ -34,7 +34,7 @@ def sentry_tunnel( try: envelope_header_line, envelope_items = request.body.split(b"\n", 1) envelope_header = to_wild_value("envelope_header", envelope_header_line.decode("utf-8")) - dsn = urllib.parse.urlparse(envelope_header["dsn"].tame(check_url)) + dsn = urlparse(envelope_header["dsn"].tame(check_url)) except Exception: raise JsonableError(_("Invalid request format")) diff --git a/zerver/webhooks/librato/tests.py b/zerver/webhooks/librato/tests.py index e9ac587d3c..d35691ebd7 100644 --- a/zerver/webhooks/librato/tests.py +++ b/zerver/webhooks/librato/tests.py @@ -1,4 +1,4 @@ -import urllib +from urllib.parse import urlencode from typing_extensions import override @@ -15,7 +15,7 @@ class LibratoHookTests(WebhookTestCase): def get_body(self, fixture_name: str) -> str: if self.IS_ATTACHMENT: return self.webhook_fixture_data("librato", fixture_name, file_type="json") - return urllib.parse.urlencode( + return urlencode( {"payload": self.webhook_fixture_data("librato", fixture_name, file_type="json")} ) diff --git a/zerver/webhooks/travis/tests.py b/zerver/webhooks/travis/tests.py index bf2f4d4897..4602fc2fb5 100644 --- a/zerver/webhooks/travis/tests.py +++ b/zerver/webhooks/travis/tests.py @@ -1,4 +1,4 @@ -import urllib +from urllib.parse import urlencode from typing_extensions import override @@ -131,6 +131,6 @@ one or more new messages. @override def get_body(self, fixture_name: str) -> str: - return urllib.parse.urlencode( + return urlencode( {"payload": self.webhook_fixture_data("travis", fixture_name, file_type="json")} ) diff --git a/zerver/worker/queue_processors.py b/zerver/worker/queue_processors.py index 99136991ba..3343d4bb20 100644 --- a/zerver/worker/queue_processors.py +++ b/zerver/worker/queue_processors.py @@ -10,7 +10,6 @@ import socket import tempfile import threading import time -import urllib from abc import ABC, abstractmethod from collections import defaultdict, deque from datetime import timedelta @@ -31,6 +30,7 @@ from typing import ( Type, TypeVar, ) +from urllib.parse import urlparse import orjson import sentry_sdk @@ -1132,7 +1132,7 @@ class DeferredWorker(QueueProcessingWorker): assert public_url is not None # Update the extra_data field now that the export is complete. - extra_data["export_path"] = urllib.parse.urlparse(public_url).path + extra_data["export_path"] = urlparse(public_url).path export_event.extra_data = extra_data export_event.save(update_fields=["extra_data"])