From 1f09cb180b8af79e1bee3391af542902279a745f Mon Sep 17 00:00:00 2001
From: Ian Metcalf <ian@metcalfbuilt.com>
Date: Thu, 15 Dec 2022 10:06:17 -0500
Subject: [PATCH 1/2] Updated naming and logic for values used in request meta

---
 locust/clients.py | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/locust/clients.py b/locust/clients.py
index 168d8cbeba..6103e6e74b 100644
--- a/locust/clients.py
+++ b/locust/clients.py
@@ -135,8 +135,11 @@ def request(self, method, url, name=None, catch_response=False, context={}, **kw
         response = self._send_request_safe_mode(method, url, **kwargs)
         response_time = (time.perf_counter() - start_perf_counter) * 1000
 
-        request_after_redirect = (response.history and response.history[0] or response).request
-        url_after_redirect = request_after_redirect.path_url
+        request_before_redirect = (response.history and response.history[0] or response).request
+        url = request_before_redirect.url
+
+        if not name:
+            name = request_before_redirect.path_url
 
         if self.user:
             context = {**self.user.context(), **context}
@@ -145,12 +148,12 @@ def request(self, method, url, name=None, catch_response=False, context={}, **kw
         request_meta = {
             "request_type": method,
             "response_time": response_time,
-            "name": name or url_after_redirect,
+            "name": name,
             "context": context,
             "response": response,
             "exception": None,
             "start_time": start_time,
-            "url": request_after_redirect.url,
+            "url": url,
         }
 
         # get the length of the content, but if the argument stream is set to True, we take

From a699a27cb215e390a3afce2bbd9c4f625cbf821d Mon Sep 17 00:00:00 2001
From: Ian Metcalf <ian@metcalfbuilt.com>
Date: Thu, 15 Dec 2022 22:02:56 -0500
Subject: [PATCH 2/2] Updated http session to always use response context
 manager

---
 locust/clients.py        | 50 ++++++++++++++++++----------------------
 locust/test/test_http.py | 16 +++++++++++++
 2 files changed, 38 insertions(+), 28 deletions(-)

diff --git a/locust/clients.py b/locust/clients.py
index 6103e6e74b..460ff6ad2b 100644
--- a/locust/clients.py
+++ b/locust/clients.py
@@ -166,34 +166,8 @@ def request(self, method, url, name=None, catch_response=False, context={}, **kw
         if catch_response:
             return ResponseContextManager(response, request_event=self.request_event, request_meta=request_meta)
         else:
-            if name:
-                # Since we use the Exception message when grouping failures, in order to not get
-                # multiple failure entries for different URLs for the same name argument, we need
-                # to temporarily override the response.url attribute
-                orig_url = response.url
-                response.url = name
-
-            try:
-                response.raise_for_status()
-            except RequestException as e:
-                while (
-                    isinstance(
-                        e,
-                        (
-                            requests.exceptions.ConnectionError,
-                            requests.packages.urllib3.exceptions.ProtocolError,
-                            requests.packages.urllib3.exceptions.MaxRetryError,
-                            requests.packages.urllib3.exceptions.NewConnectionError,
-                        ),
-                    )
-                    and e.__context__  # Not sure if the above exceptions can ever be the lowest level, but it is good to be sure
-                ):
-                    e = e.__context__
-                request_meta["exception"] = e
-
-            self.request_event.fire(**request_meta)
-            if name:
-                response.url = orig_url
+            with ResponseContextManager(response, request_event=self.request_event, request_meta=request_meta):
+                pass
             return response
 
     def _send_request_safe_mode(self, method, url, **kwargs):
@@ -256,12 +230,32 @@ def __exit__(self, exc, value, traceback):
                 # we want other unknown exceptions to be raised
                 return False
         else:
+            # Since we use the Exception message when grouping failures, in order to not get
+            # multiple failure entries for different URLs for the same name argument, we need
+            # to temporarily override the response.url attribute
+            orig_url = self.url
+            self.url = self.request_meta["name"]
+
             try:
                 self.raise_for_status()
             except requests.exceptions.RequestException as e:
+                while (
+                    isinstance(
+                        e,
+                        (
+                            requests.exceptions.ConnectionError,
+                            requests.packages.urllib3.exceptions.ProtocolError,
+                            requests.packages.urllib3.exceptions.MaxRetryError,
+                            requests.packages.urllib3.exceptions.NewConnectionError,
+                        ),
+                    )
+                    and e.__context__  # Not sure if the above exceptions can ever be the lowest level, but it is good to be sure
+                ):
+                    e = e.__context__
                 self.request_meta["exception"] = e
 
             self._report_request()
+            self.url = orig_url
 
         return True
 
diff --git a/locust/test/test_http.py b/locust/test/test_http.py
index f12bd18a91..f402d94b53 100644
--- a/locust/test/test_http.py
+++ b/locust/test/test_http.py
@@ -266,6 +266,22 @@ def test_catch_response_default_fail(self):
         self.assertEqual(1, self.environment.stats.total.num_requests)
         self.assertEqual(1, self.environment.stats.total.num_failures)
 
+    def test_catch_response_with_name_replacement(self):
+        s = self.get_client()
+        kwargs = {}
+
+        def on_request(**kw):
+            self.assertIsNotNone(kw["exception"])
+            kwargs.update(kw)
+
+        self.environment.events.request.add_listener(on_request)
+
+        with s.get("/wrong_url/01", name="replaced_url_name") as r:
+            pass
+
+        self.assertIn("for url: replaced_url_name", str(kwargs["exception"]))
+        self.assertEqual(s.base_url + "/wrong_url/01", kwargs["url"])  # url is unaffected by name
+
     def test_catch_response_missing_with_block(self):
         s = self.get_client()
         # incorrect usage, missing with-block