Repository: locustio/locust

Issue:
Add `allow_redirects` option to FastHttpSession.request
### Is your feature request related to a problem? Please describe.
I'm trying to convert my use of HttpLocust to FastHttpLocust, but I am unable to do so because my code critically relies on being able to set `allow_redirects` to False.

### Describe the solution you'd like
I want an `allow_redirects` option supported in FastHttpSession.request such that passing the value True (or not passing a value at all) will automatically perform redirects from a 3xx response and passing the value False will not perform any redirect resulting from a 3xx response.

### Describe alternatives you've considered
I have considered looking at the Referer/Location that comes back, however I'm unable to inspect the headers after the redirect has been performed. I'm also unable to find the current location after the response has been completed.

### Additional context
I need to parse the location URL where the response is saying to redirect.


Discussion:
It is super annoying, but I dont think geventhttpclient supports this, so I'm not sure we can build it (without patching geventhttpclient, which is of course possible, but pretty dirty...)
Actually, there might be a way. I was looking for a way to control timeouts and found a setting for redirects as well. I'll get back to you...
I found a (dirty) workaround. Before your request (preferably in the TaskSet.on_start() method or something) do this:

`self.client.client.redirect_resonse_codes = []`

GeventHttpClient will no longer recognize the response as a redirect and you'll be able to investigate the initial response in all its glory.
Since we’re already wrapping the geventhttpclient, I think we could implement support for an `allow_redirects` parameter pretty easily (by setting the `redirect_response_codes`).
@heyman any update on this ? 
@masthijohna Nope, not that I know of.

Resolving patch:
diff --git a/locust/contrib/fasthttp.py b/locust/contrib/fasthttp.py
--- a/locust/contrib/fasthttp.py
+++ b/locust/contrib/fasthttp.py
@@ -145,7 +145,7 @@ def _send_request_safe_mode(self, method, url, **kwargs):
             return r
     
     def request(self, method: str, path: str, name: str=None, data: str=None, catch_response: bool=False, stream: bool=False,
-                headers: dict=None, auth=None, json: dict=None, **kwargs):
+                headers: dict=None, auth=None, json: dict=None, allow_redirects=True, **kwargs):
         """
         Send and HTTP request
         Returns :py:class:`locust.contrib.fasthttp.FastResponse` object.
@@ -198,9 +198,16 @@ def request(self, method: str, path: str, name: str=None, data: str=None, catch_
             if "Accept" not in headers and "accept" not in headers:
                 headers['Accept'] = "application/json"
 
+        if not allow_redirects:
+            old_redirect_response_codes = self.client.redirect_resonse_codes
+            self.client.redirect_resonse_codes = []
+        
         # send request, and catch any exceptions
         response = self._send_request_safe_mode(method, url, payload=data, headers=headers, **kwargs)
-        
+
+        if not allow_redirects:
+            self.client.redirect_resonse_codes = old_redirect_response_codes
+
         # get the length of the content, but if the argument stream is set to True, we take
         # the size from the content-length header, in order to not trigger fetching of the body
         if stream:


Test patch:
diff --git a/locust/test/test_fasthttp.py b/locust/test/test_fasthttp.py
--- a/locust/test/test_fasthttp.py
+++ b/locust/test/test_fasthttp.py
@@ -355,6 +355,15 @@ class MyLocust(FastHttpLocust):
         l.client.get("/redirect")
         self.assertEqual(1, self.runner.stats.get("/redirect", "GET").num_failures)
 
+    def test_allow_redirects_override(self):
+        class MyLocust(FastHttpLocust):
+            host = "http://127.0.0.1:%i" % self.port
+        l = MyLocust(self.environment)
+        resp = l.client.get("/redirect", allow_redirects=False)
+        self.assertEqual("http://127.0.0.1:%i/ultra_fast" % self.port, resp.headers['location'])
+        resp = l.client.get("/redirect") # ensure redirect still works
+        self.assertFalse("location" in resp.headers)
+        
     def test_slow_redirect(self):
         s = FastHttpSession(self.environment, "http://127.0.0.1:%i" % self.port)
         url = "/redirect?url=/redirect&delay=0.5"