summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Bruhin <me@the-compiler.org>2020-04-20 18:01:38 +0200
committerFlorian Bruhin <me@the-compiler.org>2020-04-20 18:01:38 +0200
commita36f14e2ee9f7921f59bfa7aa71b7f20394f0b3b (patch)
tree6f6c0e4b4b975a8aef31459b7101aff2d0d86d4c
parent728c84158f413a2e7515ebb97eb36cbbf4c2ec2e (diff)
parent3e331f6275ecec84aca23c9b58a3d67b654d2e2a (diff)
downloadqutebrowser-a36f14e2ee9f7921f59bfa7aa71b7f20394f0b3b.tar.gz
qutebrowser-a36f14e2ee9f7921f59bfa7aa71b7f20394f0b3b.zip
Merge remote-tracking branch 'origin/pr/5314'
-rw-r--r--qutebrowser/config/configdata.yml16
-rw-r--r--qutebrowser/config/configtypes.py14
-rw-r--r--qutebrowser/utils/urlutils.py9
-rw-r--r--tests/end2end/features/yankpaste.feature4
-rw-r--r--tests/unit/config/test_configtypes.py1
-rw-r--r--tests/unit/utils/test_urlutils.py25
6 files changed, 55 insertions, 14 deletions
diff --git a/qutebrowser/config/configdata.yml b/qutebrowser/config/configdata.yml
index 0a44a9be3..effb2271c 100644
--- a/qutebrowser/config/configdata.yml
+++ b/qutebrowser/config/configdata.yml
@@ -1913,12 +1913,24 @@ url.searchengines:
name: String
forbidden: ' '
valtype: SearchEngineUrl
- desc: >-
+ desc: |
Search engines which can be used via the address bar.
Maps a search engine name (such as `DEFAULT`, or `ddg`) to a URL with a
`{}` placeholder. The placeholder will be replaced by the search term, use
- `{{` and `}}` for literal `{`/`}` signs.
+ `{{` and `}}` for literal `{`/`}` braces.
+
+ The following further placeholds are defined to configure how special
+ characters in the search terms are replaced by safe characters (called
+ 'quoting'):
+
+ * `{}` and `{semiquoted}` quote everything except slashes; this is the most
+ sensible choice for almost all search engines (for the search term
+ `slash/and&amp` this placeholder expands to `slash/and%26amp`).
+ * `{quoted}` quotes all characters (for `slash/and&amp` this placeholder
+ expands to `slash%2Fand%26amp`).
+ * `{unquoted}` quotes nothing (for `slash/and&amp` this placeholder
+ expands to `slash/and&amp`).
The search engine named `DEFAULT` is used when `url.auto_search` is turned
on and something else than a URL was entered to be opened. Other search
diff --git a/qutebrowser/config/configtypes.py b/qutebrowser/config/configtypes.py
index befc43806..3d0f5c924 100644
--- a/qutebrowser/config/configtypes.py
+++ b/qutebrowser/config/configtypes.py
@@ -1760,22 +1760,22 @@ class SearchEngineUrl(BaseType):
elif not value:
return None
- if not ('{}' in value or '{0}' in value):
+ if not re.search('{(|0|semiquoted|unquoted|quoted)}', value):
raise configexc.ValidationError(value, "must contain \"{}\"")
try:
- value.format("")
+ format_keys = {
+ 'quoted': "",
+ 'unquoted': "",
+ 'semiquoted': "",
+ }
+ value.format("", **format_keys)
except (KeyError, IndexError):
raise configexc.ValidationError(
value, "may not contain {...} (use {{ and }} for literal {/})")
except ValueError as e:
raise configexc.ValidationError(value, str(e))
- url = QUrl(value.replace('{}', 'foobar'))
- if not url.isValid():
- raise configexc.ValidationError(
- value, "invalid url, {}".format(url.errorString()))
-
return value
diff --git a/qutebrowser/utils/urlutils.py b/qutebrowser/utils/urlutils.py
index b0013c195..2df45bf12 100644
--- a/qutebrowser/utils/urlutils.py
+++ b/qutebrowser/utils/urlutils.py
@@ -116,8 +116,15 @@ def _get_search_url(txt: str) -> QUrl:
engine = 'DEFAULT'
if term:
template = config.val.url.searchengines[engine]
+ semiquoted_term = urllib.parse.quote(term)
quoted_term = urllib.parse.quote(term, safe='')
- url = qurl_from_user_input(template.format(quoted_term))
+ format_keys = {
+ 'unquoted': term,
+ 'quoted': quoted_term,
+ 'semiquoted': semiquoted_term,
+ }
+ evaluated = template.format(semiquoted_term, **format_keys)
+ url = qurl_from_user_input(evaluated)
else:
url = qurl_from_user_input(config.val.url.searchengines[engine])
url.setPath(None) # type: ignore
diff --git a/tests/end2end/features/yankpaste.feature b/tests/end2end/features/yankpaste.feature
index 46ef92a9c..16caac3a3 100644
--- a/tests/end2end/features/yankpaste.feature
+++ b/tests/end2end/features/yankpaste.feature
@@ -194,10 +194,10 @@ Feature: Yanking and pasting.
http://qutebrowser.org
should not open
And I run :open -t {clipboard}
- And I wait until data/hello.txt?q=this%20url%3A%0Ahttp%3A%2F%2Fqutebrowser.org%0Ashould%20not%20open is loaded
+ And I wait until data/hello.txt?q=this%20url%3A%0Ahttp%3A//qutebrowser.org%0Ashould%20not%20open is loaded
Then the following tabs should be open:
- about:blank
- - data/hello.txt?q=this%20url%3A%0Ahttp%3A%2F%2Fqutebrowser.org%0Ashould%20not%20open (active)
+ - data/hello.txt?q=this%20url%3A%0Ahttp%3A//qutebrowser.org%0Ashould%20not%20open (active)
Scenario: Pasting multiline whose first line looks like a URI
When I set url.auto_search to naive
diff --git a/tests/unit/config/test_configtypes.py b/tests/unit/config/test_configtypes.py
index f949e1ca0..97cb4fbf0 100644
--- a/tests/unit/config/test_configtypes.py
+++ b/tests/unit/config/test_configtypes.py
@@ -2003,7 +2003,6 @@ class TestSearchEngineUrl:
@pytest.mark.parametrize('val', [
'foo', # no placeholder
- ':{}', # invalid URL
'foo{bar}baz{}', # {bar} format string variable
'{1}{}', # numbered format string variable
'{{}', # invalid format syntax
diff --git a/tests/unit/utils/test_urlutils.py b/tests/unit/utils/test_urlutils.py
index 0c265917d..39a43479b 100644
--- a/tests/unit/utils/test_urlutils.py
+++ b/tests/unit/utils/test_urlutils.py
@@ -98,6 +98,8 @@ def init_config(config_stub):
'test': 'http://www.qutebrowser.org/?q={}',
'test-with-dash': 'http://www.example.org/?q={}',
'path-search': 'http://www.example.org/{}',
+ 'quoted-path': 'http://www.example.org/{quoted}',
+ 'unquoted': 'http://www.example.org/?{unquoted}',
'DEFAULT': 'http://www.example.com/?q={}',
}
@@ -286,8 +288,10 @@ def test_special_urls(url, special):
('blub testfoo', 'www.example.com', 'q=blub testfoo'),
('stripped ', 'www.example.com', 'q=stripped'),
('test-with-dash testfoo', 'www.example.org', 'q=testfoo'),
- ('test/with/slashes', 'www.example.com', 'q=test%2Fwith%2Fslashes'),
+ ('test/with/slashes', 'www.example.com', 'q=test/with/slashes'),
('test path-search', 'www.qutebrowser.org', 'q=path-search'),
+ ('slash/and&amp', 'www.example.com', 'q=slash/and%26amp'),
+ ('unquoted one=1&two=2', 'www.example.org', 'one=1&two=2'),
])
def test_get_search_url(config_stub, url, host, query, open_base_url):
"""Test _get_search_url().
@@ -303,6 +307,25 @@ def test_get_search_url(config_stub, url, host, query, open_base_url):
assert url.query() == query
+@pytest.mark.parametrize('open_base_url', [True, False])
+@pytest.mark.parametrize('url, host, path', [
+ ('path-search t/w/s', 'www.example.org', 't/w/s'),
+ ('quoted-path t/w/s', 'www.example.org', 't%2Fw%2Fs'),
+])
+def test_get_search_url_for_path_search(config_stub, url, host, path, open_base_url):
+ """Test _get_search_url_for_path_search().
+
+ Args:
+ url: The "URL" to enter.
+ host: The expected search machine host.
+ path: The expected path on that host that is requested.
+ """
+ config_stub.val.url.open_base_url = open_base_url
+ url = urlutils._get_search_url(url)
+ assert url.host() == host
+ assert url.path(options=QUrl.PrettyDecoded) == '/' + path
+
+
@pytest.mark.parametrize('url, host', [
('test', 'www.qutebrowser.org'),
('test-with-dash', 'www.example.org'),