We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Requests does not follow on an HTTP 301
We had already an issue when kickass redirected from https to http I seem to remember. Or it was on another engine. And the request wasn't followed so we had an empty response with status_code 301 in the engine.

Anyway, that is still the case in kickass if we try to perform a search when the query contains capitalized letters.

So why isn't 301 followed ? Is there a way to force it ?


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `searx/engines/kickass.py`
Content:
```
1 ## Kickass Torrent (Videos, Music, Files)
2 #
3 # @website     https://kickass.so
4 # @provide-api no (nothing found)
5 #
6 # @using-api   no
7 # @results     HTML (using search portal)
8 # @stable      yes (HTML can change)
9 # @parse       url, title, content, seed, leech, magnetlink
10 
11 from urlparse import urljoin
12 from cgi import escape
13 from urllib import quote
14 from lxml import html
15 from operator import itemgetter
16 from searx.engines.xpath import extract_text
17 
18 # engine dependent config
19 categories = ['videos', 'music', 'files']
20 paging = True
21 
22 # search-url
23 url = 'https://kickass.so/'
24 search_url = url + 'search/{search_term}/{pageno}/'
25 
26 # specific xpath variables
27 magnet_xpath = './/a[@title="Torrent magnet link"]'
28 torrent_xpath = './/a[@title="Download torrent file"]'
29 content_xpath = './/span[@class="font11px lightgrey block"]'
30 
31 
32 # do search-request
33 def request(query, params):
34     params['url'] = search_url.format(search_term=quote(query),
35                                       pageno=params['pageno'])
36 
37     # FIX: SSLError: hostname 'kickass.so'
38     # doesn't match either of '*.kickass.to', 'kickass.to'
39     params['verify'] = False
40 
41     return params
42 
43 
44 # get response from search-request
45 def response(resp):
46     results = []
47 
48     dom = html.fromstring(resp.text)
49 
50     search_res = dom.xpath('//table[@class="data"]//tr')
51 
52     # return empty array if nothing is found
53     if not search_res:
54         return []
55 
56     # parse results
57     for result in search_res[1:]:
58         link = result.xpath('.//a[@class="cellMainLink"]')[0]
59         href = urljoin(url, link.attrib['href'])
60         title = extract_text(link)
61         content = escape(extract_text(result.xpath(content_xpath)))
62         seed = result.xpath('.//td[contains(@class, "green")]/text()')[0]
63         leech = result.xpath('.//td[contains(@class, "red")]/text()')[0]
64         filesize = result.xpath('.//td[contains(@class, "nobr")]/text()')[0]
65         filesize_multiplier = result.xpath('.//td[contains(@class, "nobr")]//span/text()')[0]
66         files = result.xpath('.//td[contains(@class, "center")][2]/text()')[0]
67 
68         # convert seed to int if possible
69         if seed.isdigit():
70             seed = int(seed)
71         else:
72             seed = 0
73 
74         # convert leech to int if possible
75         if leech.isdigit():
76             leech = int(leech)
77         else:
78             leech = 0
79 
80         # convert filesize to byte if possible
81         try:
82             filesize = float(filesize)
83 
84             # convert filesize to byte
85             if filesize_multiplier == 'TB':
86                 filesize = int(filesize * 1024 * 1024 * 1024 * 1024)
87             elif filesize_multiplier == 'GB':
88                 filesize = int(filesize * 1024 * 1024 * 1024)
89             elif filesize_multiplier == 'MB':
90                 filesize = int(filesize * 1024 * 1024)
91             elif filesize_multiplier == 'KB':
92                 filesize = int(filesize * 1024)
93         except:
94             filesize = None
95 
96         # convert files to int if possible
97         if files.isdigit():
98             files = int(files)
99         else:
100             files = None
101 
102         magnetlink = result.xpath(magnet_xpath)[0].attrib['href']
103 
104         torrentfile = result.xpath(torrent_xpath)[0].attrib['href']
105         torrentfileurl = quote(torrentfile, safe="%/:=&?~#+!$,;'@()*")
106 
107         # append result
108         results.append({'url': href,
109                         'title': title,
110                         'content': content,
111                         'seed': seed,
112                         'leech': leech,
113                         'filesize': filesize,
114                         'files': files,
115                         'magnetlink': magnetlink,
116                         'torrentfile': torrentfileurl,
117                         'template': 'torrent.html'})
118 
119     # return results sorted by seeder
120     return sorted(results, key=itemgetter('seed'), reverse=True)
121
```
--- 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/searx/engines/kickass.py b/searx/engines/kickass.py
--- a/searx/engines/kickass.py
+++ b/searx/engines/kickass.py
@@ -20,7 +20,7 @@
 paging = True
 
 # search-url
-url = 'https://kickass.so/'
+url = 'https://kickass.to/'
 search_url = url + 'search/{search_term}/{pageno}/'
 
 # specific xpath variables
@@ -45,6 +45,11 @@
 def response(resp):
     results = []
 
+    # check if redirect comparing to the True value,
+    # because resp can be a Mock object, and any attribut name returns something.
+    if resp.is_redirect is True:
+        return results
+
     dom = html.fromstring(resp.text)
 
     search_res = dom.xpath('//table[@class="data"]//tr')

{"golden_diff": "diff --git a/searx/engines/kickass.py b/searx/engines/kickass.py\n--- a/searx/engines/kickass.py\n+++ b/searx/engines/kickass.py\n@@ -20,7 +20,7 @@\n paging = True\n \n # search-url\n-url = 'https://kickass.so/'\n+url = 'https://kickass.to/'\n search_url = url + 'search/{search_term}/{pageno}/'\n \n # specific xpath variables\n@@ -45,6 +45,11 @@\n def response(resp):\n     results = []\n \n+    # check if redirect comparing to the True value,\n+    # because resp can be a Mock object, and any attribut name returns something.\n+    if resp.is_redirect is True:\n+        return results\n+\n     dom = html.fromstring(resp.text)\n \n     search_res = dom.xpath('//table[@class=\"data\"]//tr')\n", "issue": "Requests does not follow on an HTTP 301\nWe had already an issue when kickass redirected from https to http I seem to remember. Or it was on another engine. And the request wasn't followed so we had an empty response with status_code 301 in the engine.\n\nAnyway, that is still the case in kickass if we try to perform a search when the query contains capitalized letters.\n\nSo why isn't 301 followed ? Is there a way to force it ?\n\n", "before_files": [{"content": "## Kickass Torrent (Videos, Music, Files)\n#\n# @website     https://kickass.so\n# @provide-api no (nothing found)\n#\n# @using-api   no\n# @results     HTML (using search portal)\n# @stable      yes (HTML can change)\n# @parse       url, title, content, seed, leech, magnetlink\n\nfrom urlparse import urljoin\nfrom cgi import escape\nfrom urllib import quote\nfrom lxml import html\nfrom operator import itemgetter\nfrom searx.engines.xpath import extract_text\n\n# engine dependent config\ncategories = ['videos', 'music', 'files']\npaging = True\n\n# search-url\nurl = 'https://kickass.so/'\nsearch_url = url + 'search/{search_term}/{pageno}/'\n\n# specific xpath variables\nmagnet_xpath = './/a[@title=\"Torrent magnet link\"]'\ntorrent_xpath = './/a[@title=\"Download torrent file\"]'\ncontent_xpath = './/span[@class=\"font11px lightgrey block\"]'\n\n\n# do search-request\ndef request(query, params):\n    params['url'] = search_url.format(search_term=quote(query),\n                                      pageno=params['pageno'])\n\n    # FIX: SSLError: hostname 'kickass.so'\n    # doesn't match either of '*.kickass.to', 'kickass.to'\n    params['verify'] = False\n\n    return params\n\n\n# get response from search-request\ndef response(resp):\n    results = []\n\n    dom = html.fromstring(resp.text)\n\n    search_res = dom.xpath('//table[@class=\"data\"]//tr')\n\n    # return empty array if nothing is found\n    if not search_res:\n        return []\n\n    # parse results\n    for result in search_res[1:]:\n        link = result.xpath('.//a[@class=\"cellMainLink\"]')[0]\n        href = urljoin(url, link.attrib['href'])\n        title = extract_text(link)\n        content = escape(extract_text(result.xpath(content_xpath)))\n        seed = result.xpath('.//td[contains(@class, \"green\")]/text()')[0]\n        leech = result.xpath('.//td[contains(@class, \"red\")]/text()')[0]\n        filesize = result.xpath('.//td[contains(@class, \"nobr\")]/text()')[0]\n        filesize_multiplier = result.xpath('.//td[contains(@class, \"nobr\")]//span/text()')[0]\n        files = result.xpath('.//td[contains(@class, \"center\")][2]/text()')[0]\n\n        # convert seed to int if possible\n        if seed.isdigit():\n            seed = int(seed)\n        else:\n            seed = 0\n\n        # convert leech to int if possible\n        if leech.isdigit():\n            leech = int(leech)\n        else:\n            leech = 0\n\n        # convert filesize to byte if possible\n        try:\n            filesize = float(filesize)\n\n            # convert filesize to byte\n            if filesize_multiplier == 'TB':\n                filesize = int(filesize * 1024 * 1024 * 1024 * 1024)\n            elif filesize_multiplier == 'GB':\n                filesize = int(filesize * 1024 * 1024 * 1024)\n            elif filesize_multiplier == 'MB':\n                filesize = int(filesize * 1024 * 1024)\n            elif filesize_multiplier == 'KB':\n                filesize = int(filesize * 1024)\n        except:\n            filesize = None\n\n        # convert files to int if possible\n        if files.isdigit():\n            files = int(files)\n        else:\n            files = None\n\n        magnetlink = result.xpath(magnet_xpath)[0].attrib['href']\n\n        torrentfile = result.xpath(torrent_xpath)[0].attrib['href']\n        torrentfileurl = quote(torrentfile, safe=\"%/:=&?~#+!$,;'@()*\")\n\n        # append result\n        results.append({'url': href,\n                        'title': title,\n                        'content': content,\n                        'seed': seed,\n                        'leech': leech,\n                        'filesize': filesize,\n                        'files': files,\n                        'magnetlink': magnetlink,\n                        'torrentfile': torrentfileurl,\n                        'template': 'torrent.html'})\n\n    # return results sorted by seeder\n    return sorted(results, key=itemgetter('seed'), reverse=True)\n", "path": "searx/engines/kickass.py"}], "after_files": [{"content": "## Kickass Torrent (Videos, Music, Files)\n#\n# @website     https://kickass.so\n# @provide-api no (nothing found)\n#\n# @using-api   no\n# @results     HTML (using search portal)\n# @stable      yes (HTML can change)\n# @parse       url, title, content, seed, leech, magnetlink\n\nfrom urlparse import urljoin\nfrom cgi import escape\nfrom urllib import quote\nfrom lxml import html\nfrom operator import itemgetter\nfrom searx.engines.xpath import extract_text\n\n# engine dependent config\ncategories = ['videos', 'music', 'files']\npaging = True\n\n# search-url\nurl = 'https://kickass.to/'\nsearch_url = url + 'search/{search_term}/{pageno}/'\n\n# specific xpath variables\nmagnet_xpath = './/a[@title=\"Torrent magnet link\"]'\ntorrent_xpath = './/a[@title=\"Download torrent file\"]'\ncontent_xpath = './/span[@class=\"font11px lightgrey block\"]'\n\n\n# do search-request\ndef request(query, params):\n    params['url'] = search_url.format(search_term=quote(query),\n                                      pageno=params['pageno'])\n\n    # FIX: SSLError: hostname 'kickass.so'\n    # doesn't match either of '*.kickass.to', 'kickass.to'\n    params['verify'] = False\n\n    return params\n\n\n# get response from search-request\ndef response(resp):\n    results = []\n\n    # check if redirect comparing to the True value,\n    # because resp can be a Mock object, and any attribut name returns something.\n    if resp.is_redirect is True:\n        return results\n\n    dom = html.fromstring(resp.text)\n\n    search_res = dom.xpath('//table[@class=\"data\"]//tr')\n\n    # return empty array if nothing is found\n    if not search_res:\n        return []\n\n    # parse results\n    for result in search_res[1:]:\n        link = result.xpath('.//a[@class=\"cellMainLink\"]')[0]\n        href = urljoin(url, link.attrib['href'])\n        title = extract_text(link)\n        content = escape(extract_text(result.xpath(content_xpath)))\n        seed = result.xpath('.//td[contains(@class, \"green\")]/text()')[0]\n        leech = result.xpath('.//td[contains(@class, \"red\")]/text()')[0]\n        filesize = result.xpath('.//td[contains(@class, \"nobr\")]/text()')[0]\n        filesize_multiplier = result.xpath('.//td[contains(@class, \"nobr\")]//span/text()')[0]\n        files = result.xpath('.//td[contains(@class, \"center\")][2]/text()')[0]\n\n        # convert seed to int if possible\n        if seed.isdigit():\n            seed = int(seed)\n        else:\n            seed = 0\n\n        # convert leech to int if possible\n        if leech.isdigit():\n            leech = int(leech)\n        else:\n            leech = 0\n\n        # convert filesize to byte if possible\n        try:\n            filesize = float(filesize)\n\n            # convert filesize to byte\n            if filesize_multiplier == 'TB':\n                filesize = int(filesize * 1024 * 1024 * 1024 * 1024)\n            elif filesize_multiplier == 'GB':\n                filesize = int(filesize * 1024 * 1024 * 1024)\n            elif filesize_multiplier == 'MB':\n                filesize = int(filesize * 1024 * 1024)\n            elif filesize_multiplier == 'KB':\n                filesize = int(filesize * 1024)\n        except:\n            filesize = None\n\n        # convert files to int if possible\n        if files.isdigit():\n            files = int(files)\n        else:\n            files = None\n\n        magnetlink = result.xpath(magnet_xpath)[0].attrib['href']\n\n        torrentfile = result.xpath(torrent_xpath)[0].attrib['href']\n        torrentfileurl = quote(torrentfile, safe=\"%/:=&?~#+!$,;'@()*\")\n\n        # append result\n        results.append({'url': href,\n                        'title': title,\n                        'content': content,\n                        'seed': seed,\n                        'leech': leech,\n                        'filesize': filesize,\n                        'files': files,\n                        'magnetlink': magnetlink,\n                        'torrentfile': torrentfileurl,\n                        'template': 'torrent.html'})\n\n    # return results sorted by seeder\n    return sorted(results, key=itemgetter('seed'), reverse=True)\n", "path": "searx/engines/kickass.py"}]}