We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Error 302 redirection with headers location starts with 3 slash

### Description

when the 302 response return a headers's location startswith 3 slash, the scrapy redirect to a url different from what the browser do.

### Steps to Reproduce

1.  scrapy shell https://www.hjenglish.com/new/p1285798/

**Expected behavior:** 
redirect to `https://fr.hujiang.com/new/p1285798/` as browser `Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36`  do.


**Actual behavior:** 
redirct to `https://www.hjenglish.com/fr.hujiang.com/new/p1285798`

**Reproduces how often:** 

everytime

### Versions
Scrapy       : 1.7.3
lxml         : 4.3.2.0
libxml2      : 2.9.9
cssselect    : 1.1.0
parsel       : 1.5.2
w3lib        : 1.20.0
Twisted      : 19.7.0
Python       : 3.7.3 (default, Mar 27 2019, 17:13:21) [MSC v.1915 64 bit (AMD64)]
pyOpenSSL    : 19.0.0 (OpenSSL 1.1.1c  28 May 2019)
cryptography : 2.6.1
Platform     : Windows-10-10.0.17134-SP0


### Additional context

I check the defination of [Location in rfc](https://tools.ietf.org/html/rfc7231#section-7.1.2) and end with [reference resolution](https://tools.ietf.org/html/rfc3986#section-5.3). But I fail to findout how to resolve the Location startswith `///`. So I don't know why Chrome did so.

The behavior of scrapy is determined by [redirect.py#L73](https://github.com/scrapy/scrapy/blob/master/scrapy/downloadermiddlewares/redirect.py#L73), which will truncate `///` to `/`。

I'm wandering the differents betweent scarpy and browser...


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `scrapy/downloadermiddlewares/redirect.py`
Content:
```
1 import logging
2 from six.moves.urllib.parse import urljoin
3 
4 from w3lib.url import safe_url_string
5 
6 from scrapy.http import HtmlResponse
7 from scrapy.utils.response import get_meta_refresh
8 from scrapy.exceptions import IgnoreRequest, NotConfigured
9 
10 logger = logging.getLogger(__name__)
11 
12 
13 class BaseRedirectMiddleware(object):
14 
15     enabled_setting = 'REDIRECT_ENABLED'
16 
17     def __init__(self, settings):
18         if not settings.getbool(self.enabled_setting):
19             raise NotConfigured
20 
21         self.max_redirect_times = settings.getint('REDIRECT_MAX_TIMES')
22         self.priority_adjust = settings.getint('REDIRECT_PRIORITY_ADJUST')
23 
24     @classmethod
25     def from_crawler(cls, crawler):
26         return cls(crawler.settings)
27 
28     def _redirect(self, redirected, request, spider, reason):
29         ttl = request.meta.setdefault('redirect_ttl', self.max_redirect_times)
30         redirects = request.meta.get('redirect_times', 0) + 1
31 
32         if ttl and redirects <= self.max_redirect_times:
33             redirected.meta['redirect_times'] = redirects
34             redirected.meta['redirect_ttl'] = ttl - 1
35             redirected.meta['redirect_urls'] = request.meta.get('redirect_urls', []) + \
36                 [request.url]
37             redirected.meta['redirect_reasons'] = request.meta.get('redirect_reasons', []) + \
38                 [reason]
39             redirected.dont_filter = request.dont_filter
40             redirected.priority = request.priority + self.priority_adjust
41             logger.debug("Redirecting (%(reason)s) to %(redirected)s from %(request)s",
42                          {'reason': reason, 'redirected': redirected, 'request': request},
43                          extra={'spider': spider})
44             return redirected
45         else:
46             logger.debug("Discarding %(request)s: max redirections reached",
47                          {'request': request}, extra={'spider': spider})
48             raise IgnoreRequest("max redirections reached")
49 
50     def _redirect_request_using_get(self, request, redirect_url):
51         redirected = request.replace(url=redirect_url, method='GET', body='')
52         redirected.headers.pop('Content-Type', None)
53         redirected.headers.pop('Content-Length', None)
54         return redirected
55 
56 
57 class RedirectMiddleware(BaseRedirectMiddleware):
58     """
59     Handle redirection of requests based on response status
60     and meta-refresh html tag.
61     """
62     def process_response(self, request, response, spider):
63         if (request.meta.get('dont_redirect', False) or
64                 response.status in getattr(spider, 'handle_httpstatus_list', []) or
65                 response.status in request.meta.get('handle_httpstatus_list', []) or
66                 request.meta.get('handle_httpstatus_all', False)):
67             return response
68 
69         allowed_status = (301, 302, 303, 307, 308)
70         if 'Location' not in response.headers or response.status not in allowed_status:
71             return response
72 
73         location = safe_url_string(response.headers['location'])
74 
75         redirected_url = urljoin(request.url, location)
76 
77         if response.status in (301, 307, 308) or request.method == 'HEAD':
78             redirected = request.replace(url=redirected_url)
79             return self._redirect(redirected, request, spider, response.status)
80 
81         redirected = self._redirect_request_using_get(request, redirected_url)
82         return self._redirect(redirected, request, spider, response.status)
83 
84 
85 class MetaRefreshMiddleware(BaseRedirectMiddleware):
86 
87     enabled_setting = 'METAREFRESH_ENABLED'
88 
89     def __init__(self, settings):
90         super(MetaRefreshMiddleware, self).__init__(settings)
91         self._ignore_tags = settings.getlist('METAREFRESH_IGNORE_TAGS')
92         self._maxdelay = settings.getint('REDIRECT_MAX_METAREFRESH_DELAY',
93                                          settings.getint('METAREFRESH_MAXDELAY'))
94 
95     def process_response(self, request, response, spider):
96         if request.meta.get('dont_redirect', False) or request.method == 'HEAD' or \
97                 not isinstance(response, HtmlResponse):
98             return response
99 
100         interval, url = get_meta_refresh(response,
101                                          ignore_tags=self._ignore_tags)
102         if url and interval < self._maxdelay:
103             redirected = self._redirect_request_using_get(request, url)
104             return self._redirect(redirected, request, spider, 'meta refresh')
105 
106         return response
107
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/scrapy/downloadermiddlewares/redirect.py b/scrapy/downloadermiddlewares/redirect.py
--- a/scrapy/downloadermiddlewares/redirect.py
+++ b/scrapy/downloadermiddlewares/redirect.py
@@ -1,5 +1,5 @@
 import logging
-from six.moves.urllib.parse import urljoin
+from six.moves.urllib.parse import urljoin, urlparse
 
 from w3lib.url import safe_url_string
 
@@ -70,7 +70,10 @@
         if 'Location' not in response.headers or response.status not in allowed_status:
             return response
 
-        location = safe_url_string(response.headers['location'])
+        location = safe_url_string(response.headers['Location'])
+        if response.headers['Location'].startswith(b'//'):
+            request_scheme = urlparse(request.url).scheme
+            location = request_scheme + '://' + location.lstrip('/')
 
         redirected_url = urljoin(request.url, location)

{"golden_diff": "diff --git a/scrapy/downloadermiddlewares/redirect.py b/scrapy/downloadermiddlewares/redirect.py\n--- a/scrapy/downloadermiddlewares/redirect.py\n+++ b/scrapy/downloadermiddlewares/redirect.py\n@@ -1,5 +1,5 @@\n import logging\n-from six.moves.urllib.parse import urljoin\n+from six.moves.urllib.parse import urljoin, urlparse\n \n from w3lib.url import safe_url_string\n \n@@ -70,7 +70,10 @@\n         if 'Location' not in response.headers or response.status not in allowed_status:\n             return response\n \n-        location = safe_url_string(response.headers['location'])\n+        location = safe_url_string(response.headers['Location'])\n+        if response.headers['Location'].startswith(b'//'):\n+            request_scheme = urlparse(request.url).scheme\n+            location = request_scheme + '://' + location.lstrip('/')\n \n         redirected_url = urljoin(request.url, location)\n", "issue": "Error 302 redirection with headers location starts with 3 slash\n\r\n### Description\r\n\r\nwhen the 302 response return a headers's location startswith 3 slash, the scrapy redirect to a url different from what the browser do.\r\n\r\n### Steps to Reproduce\r\n\r\n1.  scrapy shell https://www.hjenglish.com/new/p1285798/\r\n\r\n**Expected behavior:** \r\nredirect to `https://fr.hujiang.com/new/p1285798/` as browser `Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36`  do.\r\n\r\n\r\n**Actual behavior:** \r\nredirct to `https://www.hjenglish.com/fr.hujiang.com/new/p1285798`\r\n\r\n**Reproduces how often:** \r\n\r\neverytime\r\n\r\n### Versions\r\nScrapy       : 1.7.3\r\nlxml         : 4.3.2.0\r\nlibxml2      : 2.9.9\r\ncssselect    : 1.1.0\r\nparsel       : 1.5.2\r\nw3lib        : 1.20.0\r\nTwisted      : 19.7.0\r\nPython       : 3.7.3 (default, Mar 27 2019, 17:13:21) [MSC v.1915 64 bit (AMD64)]\r\npyOpenSSL    : 19.0.0 (OpenSSL 1.1.1c  28 May 2019)\r\ncryptography : 2.6.1\r\nPlatform     : Windows-10-10.0.17134-SP0\r\n\r\n\r\n### Additional context\r\n\r\nI check the defination of [Location in rfc](https://tools.ietf.org/html/rfc7231#section-7.1.2) and end with [reference resolution](https://tools.ietf.org/html/rfc3986#section-5.3). But I fail to findout how to resolve the Location startswith `///`. So I don't know why Chrome did so.\r\n\r\nThe behavior of scrapy is determined by [redirect.py#L73](https://github.com/scrapy/scrapy/blob/master/scrapy/downloadermiddlewares/redirect.py#L73), which will truncate `///` to `/`\u3002\r\n\r\nI'm wandering the differents betweent scarpy and browser...\r\n\n", "before_files": [{"content": "import logging\nfrom six.moves.urllib.parse import urljoin\n\nfrom w3lib.url import safe_url_string\n\nfrom scrapy.http import HtmlResponse\nfrom scrapy.utils.response import get_meta_refresh\nfrom scrapy.exceptions import IgnoreRequest, NotConfigured\n\nlogger = logging.getLogger(__name__)\n\n\nclass BaseRedirectMiddleware(object):\n\n    enabled_setting = 'REDIRECT_ENABLED'\n\n    def __init__(self, settings):\n        if not settings.getbool(self.enabled_setting):\n            raise NotConfigured\n\n        self.max_redirect_times = settings.getint('REDIRECT_MAX_TIMES')\n        self.priority_adjust = settings.getint('REDIRECT_PRIORITY_ADJUST')\n\n    @classmethod\n    def from_crawler(cls, crawler):\n        return cls(crawler.settings)\n\n    def _redirect(self, redirected, request, spider, reason):\n        ttl = request.meta.setdefault('redirect_ttl', self.max_redirect_times)\n        redirects = request.meta.get('redirect_times', 0) + 1\n\n        if ttl and redirects <= self.max_redirect_times:\n            redirected.meta['redirect_times'] = redirects\n            redirected.meta['redirect_ttl'] = ttl - 1\n            redirected.meta['redirect_urls'] = request.meta.get('redirect_urls', []) + \\\n                [request.url]\n            redirected.meta['redirect_reasons'] = request.meta.get('redirect_reasons', []) + \\\n                [reason]\n            redirected.dont_filter = request.dont_filter\n            redirected.priority = request.priority + self.priority_adjust\n            logger.debug(\"Redirecting (%(reason)s) to %(redirected)s from %(request)s\",\n                         {'reason': reason, 'redirected': redirected, 'request': request},\n                         extra={'spider': spider})\n            return redirected\n        else:\n            logger.debug(\"Discarding %(request)s: max redirections reached\",\n                         {'request': request}, extra={'spider': spider})\n            raise IgnoreRequest(\"max redirections reached\")\n\n    def _redirect_request_using_get(self, request, redirect_url):\n        redirected = request.replace(url=redirect_url, method='GET', body='')\n        redirected.headers.pop('Content-Type', None)\n        redirected.headers.pop('Content-Length', None)\n        return redirected\n\n\nclass RedirectMiddleware(BaseRedirectMiddleware):\n    \"\"\"\n    Handle redirection of requests based on response status\n    and meta-refresh html tag.\n    \"\"\"\n    def process_response(self, request, response, spider):\n        if (request.meta.get('dont_redirect', False) or\n                response.status in getattr(spider, 'handle_httpstatus_list', []) or\n                response.status in request.meta.get('handle_httpstatus_list', []) or\n                request.meta.get('handle_httpstatus_all', False)):\n            return response\n\n        allowed_status = (301, 302, 303, 307, 308)\n        if 'Location' not in response.headers or response.status not in allowed_status:\n            return response\n\n        location = safe_url_string(response.headers['location'])\n\n        redirected_url = urljoin(request.url, location)\n\n        if response.status in (301, 307, 308) or request.method == 'HEAD':\n            redirected = request.replace(url=redirected_url)\n            return self._redirect(redirected, request, spider, response.status)\n\n        redirected = self._redirect_request_using_get(request, redirected_url)\n        return self._redirect(redirected, request, spider, response.status)\n\n\nclass MetaRefreshMiddleware(BaseRedirectMiddleware):\n\n    enabled_setting = 'METAREFRESH_ENABLED'\n\n    def __init__(self, settings):\n        super(MetaRefreshMiddleware, self).__init__(settings)\n        self._ignore_tags = settings.getlist('METAREFRESH_IGNORE_TAGS')\n        self._maxdelay = settings.getint('REDIRECT_MAX_METAREFRESH_DELAY',\n                                         settings.getint('METAREFRESH_MAXDELAY'))\n\n    def process_response(self, request, response, spider):\n        if request.meta.get('dont_redirect', False) or request.method == 'HEAD' or \\\n                not isinstance(response, HtmlResponse):\n            return response\n\n        interval, url = get_meta_refresh(response,\n                                         ignore_tags=self._ignore_tags)\n        if url and interval < self._maxdelay:\n            redirected = self._redirect_request_using_get(request, url)\n            return self._redirect(redirected, request, spider, 'meta refresh')\n\n        return response\n", "path": "scrapy/downloadermiddlewares/redirect.py"}], "after_files": [{"content": "import logging\nfrom six.moves.urllib.parse import urljoin, urlparse\n\nfrom w3lib.url import safe_url_string\n\nfrom scrapy.http import HtmlResponse\nfrom scrapy.utils.response import get_meta_refresh\nfrom scrapy.exceptions import IgnoreRequest, NotConfigured\n\nlogger = logging.getLogger(__name__)\n\n\nclass BaseRedirectMiddleware(object):\n\n    enabled_setting = 'REDIRECT_ENABLED'\n\n    def __init__(self, settings):\n        if not settings.getbool(self.enabled_setting):\n            raise NotConfigured\n\n        self.max_redirect_times = settings.getint('REDIRECT_MAX_TIMES')\n        self.priority_adjust = settings.getint('REDIRECT_PRIORITY_ADJUST')\n\n    @classmethod\n    def from_crawler(cls, crawler):\n        return cls(crawler.settings)\n\n    def _redirect(self, redirected, request, spider, reason):\n        ttl = request.meta.setdefault('redirect_ttl', self.max_redirect_times)\n        redirects = request.meta.get('redirect_times', 0) + 1\n\n        if ttl and redirects <= self.max_redirect_times:\n            redirected.meta['redirect_times'] = redirects\n            redirected.meta['redirect_ttl'] = ttl - 1\n            redirected.meta['redirect_urls'] = request.meta.get('redirect_urls', []) + \\\n                [request.url]\n            redirected.meta['redirect_reasons'] = request.meta.get('redirect_reasons', []) + \\\n                [reason]\n            redirected.dont_filter = request.dont_filter\n            redirected.priority = request.priority + self.priority_adjust\n            logger.debug(\"Redirecting (%(reason)s) to %(redirected)s from %(request)s\",\n                         {'reason': reason, 'redirected': redirected, 'request': request},\n                         extra={'spider': spider})\n            return redirected\n        else:\n            logger.debug(\"Discarding %(request)s: max redirections reached\",\n                         {'request': request}, extra={'spider': spider})\n            raise IgnoreRequest(\"max redirections reached\")\n\n    def _redirect_request_using_get(self, request, redirect_url):\n        redirected = request.replace(url=redirect_url, method='GET', body='')\n        redirected.headers.pop('Content-Type', None)\n        redirected.headers.pop('Content-Length', None)\n        return redirected\n\n\nclass RedirectMiddleware(BaseRedirectMiddleware):\n    \"\"\"\n    Handle redirection of requests based on response status\n    and meta-refresh html tag.\n    \"\"\"\n    def process_response(self, request, response, spider):\n        if (request.meta.get('dont_redirect', False) or\n                response.status in getattr(spider, 'handle_httpstatus_list', []) or\n                response.status in request.meta.get('handle_httpstatus_list', []) or\n                request.meta.get('handle_httpstatus_all', False)):\n            return response\n\n        allowed_status = (301, 302, 303, 307, 308)\n        if 'Location' not in response.headers or response.status not in allowed_status:\n            return response\n\n        location = safe_url_string(response.headers['Location'])\n        if response.headers['Location'].startswith(b'//'):\n            request_scheme = urlparse(request.url).scheme\n            location = request_scheme + '://' + location.lstrip('/')\n\n        redirected_url = urljoin(request.url, location)\n\n        if response.status in (301, 307, 308) or request.method == 'HEAD':\n            redirected = request.replace(url=redirected_url)\n            return self._redirect(redirected, request, spider, response.status)\n\n        redirected = self._redirect_request_using_get(request, redirected_url)\n        return self._redirect(redirected, request, spider, response.status)\n\n\nclass MetaRefreshMiddleware(BaseRedirectMiddleware):\n\n    enabled_setting = 'METAREFRESH_ENABLED'\n\n    def __init__(self, settings):\n        super(MetaRefreshMiddleware, self).__init__(settings)\n        self._ignore_tags = settings.getlist('METAREFRESH_IGNORE_TAGS')\n        self._maxdelay = settings.getint('REDIRECT_MAX_METAREFRESH_DELAY',\n                                         settings.getint('METAREFRESH_MAXDELAY'))\n\n    def process_response(self, request, response, spider):\n        if request.meta.get('dont_redirect', False) or request.method == 'HEAD' or \\\n                not isinstance(response, HtmlResponse):\n            return response\n\n        interval, url = get_meta_refresh(response,\n                                         ignore_tags=self._ignore_tags)\n        if url and interval < self._maxdelay:\n            redirected = self._redirect_request_using_get(request, url)\n            return self._redirect(redirected, request, spider, 'meta refresh')\n\n        return response\n", "path": "scrapy/downloadermiddlewares/redirect.py"}]}