Commit 584aaee5 by David Hotham Committed by GitHub

add timeouts to all requests (#5881)

* add timeouts to all requests
* make the requests timeout a constant
* 15s (matching the default in pip)
parent a3aafa84
...@@ -22,6 +22,7 @@ from requests_toolbelt.multipart import MultipartEncoderMonitor ...@@ -22,6 +22,7 @@ from requests_toolbelt.multipart import MultipartEncoderMonitor
from urllib3 import util from urllib3 import util
from poetry.__version__ import __version__ from poetry.__version__ import __version__
from poetry.utils.constants import REQUESTS_TIMEOUT
from poetry.utils.patterns import wheel_file_re from poetry.utils.patterns import wheel_file_re
...@@ -262,6 +263,7 @@ class Uploader: ...@@ -262,6 +263,7 @@ class Uploader:
data=monitor, data=monitor,
allow_redirects=False, allow_redirects=False,
headers={"Content-Type": monitor.content_type}, headers={"Content-Type": monitor.content_type},
timeout=REQUESTS_TIMEOUT,
) )
if resp is None or 200 <= resp.status_code < 300: if resp is None or 200 <= resp.status_code < 300:
bar.set_format( bar.set_format(
...@@ -320,6 +322,7 @@ class Uploader: ...@@ -320,6 +322,7 @@ class Uploader:
data=encoder, data=encoder,
allow_redirects=False, allow_redirects=False,
headers={"Content-Type": encoder.content_type}, headers={"Content-Type": encoder.content_type},
timeout=REQUESTS_TIMEOUT,
) )
resp.raise_for_status() resp.raise_for_status()
......
...@@ -24,6 +24,7 @@ from poetry.repositories.exceptions import PackageNotFound ...@@ -24,6 +24,7 @@ from poetry.repositories.exceptions import PackageNotFound
from poetry.repositories.exceptions import RepositoryError from poetry.repositories.exceptions import RepositoryError
from poetry.repositories.link_sources.html import HTMLPage from poetry.repositories.link_sources.html import HTMLPage
from poetry.utils.authenticator import Authenticator from poetry.utils.authenticator import Authenticator
from poetry.utils.constants import REQUESTS_TIMEOUT
from poetry.utils.helpers import download_file from poetry.utils.helpers import download_file
from poetry.utils.patterns import wheel_file_re from poetry.utils.patterns import wheel_file_re
...@@ -260,7 +261,9 @@ class HTTPRepository(CachedRepository, ABC): ...@@ -260,7 +261,9 @@ class HTTPRepository(CachedRepository, ABC):
def _get_response(self, endpoint: str) -> requests.Response | None: def _get_response(self, endpoint: str) -> requests.Response | None:
url = self._url + endpoint url = self._url + endpoint
try: try:
response: requests.Response = self.session.get(url, raise_for_status=False) response: requests.Response = self.session.get(
url, raise_for_status=False, timeout=REQUESTS_TIMEOUT
)
if response.status_code in (401, 403): if response.status_code in (401, 403):
self._log( self._log(
f"Authorization error accessing {url}", f"Authorization error accessing {url}",
......
...@@ -17,6 +17,7 @@ from poetry.core.version.exceptions import InvalidVersion ...@@ -17,6 +17,7 @@ from poetry.core.version.exceptions import InvalidVersion
from poetry.repositories.exceptions import PackageNotFound from poetry.repositories.exceptions import PackageNotFound
from poetry.repositories.http import HTTPRepository from poetry.repositories.http import HTTPRepository
from poetry.utils._compat import to_str from poetry.utils._compat import to_str
from poetry.utils.constants import REQUESTS_TIMEOUT
cache_control_logger.setLevel(logging.ERROR) cache_control_logger.setLevel(logging.ERROR)
...@@ -103,7 +104,9 @@ class PyPiRepository(HTTPRepository): ...@@ -103,7 +104,9 @@ class PyPiRepository(HTTPRepository):
search = {"q": query} search = {"q": query}
response = requests.session().get(self._base_url + "search", params=search) response = requests.session().get(
self._base_url + "search", params=search, timeout=REQUESTS_TIMEOUT
)
content = parse(response.content, namespaceHTMLElements=False) content = parse(response.content, namespaceHTMLElements=False)
for result in content.findall(".//*[@class='package-snippet']"): for result in content.findall(".//*[@class='package-snippet']"):
name_element = result.find("h3/*[@class='package-snippet__name']") name_element = result.find("h3/*[@class='package-snippet__name']")
...@@ -244,14 +247,18 @@ class PyPiRepository(HTTPRepository): ...@@ -244,14 +247,18 @@ class PyPiRepository(HTTPRepository):
def _get(self, endpoint: str) -> dict[str, Any] | None: def _get(self, endpoint: str) -> dict[str, Any] | None:
try: try:
json_response = self.session.get( json_response = self.session.get(
self._base_url + endpoint, raise_for_status=False self._base_url + endpoint,
raise_for_status=False,
timeout=REQUESTS_TIMEOUT,
) )
except requests.exceptions.TooManyRedirects: except requests.exceptions.TooManyRedirects:
# Cache control redirect loop. # Cache control redirect loop.
# We try to remove the cache and try again # We try to remove the cache and try again
self.session.delete_cache(self._base_url + endpoint) self.session.delete_cache(self._base_url + endpoint)
json_response = self.session.get( json_response = self.session.get(
self._base_url + endpoint, raise_for_status=False self._base_url + endpoint,
raise_for_status=False,
timeout=REQUESTS_TIMEOUT,
) )
if json_response.status_code != 200: if json_response.status_code != 200:
......
...@@ -21,6 +21,7 @@ from cachecontrol.caches import FileCache ...@@ -21,6 +21,7 @@ from cachecontrol.caches import FileCache
from poetry.config.config import Config from poetry.config.config import Config
from poetry.exceptions import PoetryException from poetry.exceptions import PoetryException
from poetry.utils.constants import REQUESTS_TIMEOUT
from poetry.utils.password_manager import HTTPAuthCredential from poetry.utils.password_manager import HTTPAuthCredential
from poetry.utils.password_manager import PasswordManager from poetry.utils.password_manager import PasswordManager
...@@ -219,7 +220,7 @@ class Authenticator: ...@@ -219,7 +220,7 @@ class Authenticator:
# Send the request. # Send the request.
send_kwargs = { send_kwargs = {
"timeout": kwargs.get("timeout"), "timeout": kwargs.get("timeout", REQUESTS_TIMEOUT),
"allow_redirects": kwargs.get("allow_redirects", True), "allow_redirects": kwargs.get("allow_redirects", True),
} }
send_kwargs.update(settings) send_kwargs.update(settings)
......
from __future__ import annotations
# Timeout for HTTP requests using the requests library.
REQUESTS_TIMEOUT = 15
...@@ -13,6 +13,8 @@ from typing import Any ...@@ -13,6 +13,8 @@ from typing import Any
from typing import Iterator from typing import Iterator
from typing import Mapping from typing import Mapping
from poetry.utils.constants import REQUESTS_TIMEOUT
if TYPE_CHECKING: if TYPE_CHECKING:
from collections.abc import Callable from collections.abc import Callable
...@@ -89,7 +91,7 @@ def download_file( ...@@ -89,7 +91,7 @@ def download_file(
get = requests.get if not session else session.get get = requests.get if not session else session.get
response = get(url, stream=True) response = get(url, stream=True, timeout=REQUESTS_TIMEOUT)
response.raise_for_status() response.raise_for_status()
set_indicator = False set_indicator = False
......
...@@ -426,7 +426,9 @@ def test_get_redirected_response_url( ...@@ -426,7 +426,9 @@ def test_get_redirected_response_url(
repo = MockHttpRepository({"/foo": 200}, http) repo = MockHttpRepository({"/foo": 200}, http)
redirect_url = "http://legacy.redirect.bar" redirect_url = "http://legacy.redirect.bar"
def get_mock(url: str, raise_for_status: bool = True) -> requests.Response: def get_mock(
url: str, raise_for_status: bool = True, timeout: int = 5
) -> requests.Response:
response = requests.Response() response = requests.Response()
response.status_code = 200 response.status_code = 200
response.url = redirect_url + "/foo" response.url = redirect_url + "/foo"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment