33# standard
44from functools import lru_cache
55import re
6- from urllib .parse import unquote , urlsplit
6+ from urllib .parse import parse_qs , unquote , urlsplit
77
88# local
99from .hostname import hostname
@@ -34,11 +34,6 @@ def _path_regex():
3434 )
3535
3636
37- @lru_cache
38- def _query_regex ():
39- return re .compile (r"&?(\w+=?[^\s&]*)" , re .IGNORECASE )
40-
41-
4237def _validate_scheme (value : str ):
4338 """Validate scheme."""
4439 # More schemes will be considered later.
@@ -108,16 +103,16 @@ def _validate_netloc(
108103 ) and _validate_auth_segment (basic_auth )
109104
110105
111- def _validate_optionals (path : str , query : str , fragment : str ):
106+ def _validate_optionals (path : str , query : str , fragment : str , strict_query : bool ):
112107 """Validate path query and fragments."""
113108 optional_segments = True
114109 if path :
115110 optional_segments &= bool (_path_regex ().match (path ))
116- if query :
117- optional_segments &= bool ( _query_regex (). match ( query ))
111+ if query and parse_qs ( query , strict_parsing = strict_query ) :
112+ optional_segments &= True
118113 if fragment :
119114 fragment = fragment .lstrip ("/" ) if fragment .startswith ("/" ) else fragment
120- optional_segments &= all (char_to_avoid not in fragment for char_to_avoid in ("/" , "?" ))
115+ optional_segments &= all (char_to_avoid not in fragment for char_to_avoid in ("?" , ))
121116 return optional_segments
122117
123118
@@ -130,6 +125,7 @@ def url(
130125 skip_ipv4_addr : bool = False ,
131126 may_have_port : bool = True ,
132127 simple_host : bool = False ,
128+ strict_query : bool = True ,
133129 rfc_1034 : bool = False ,
134130 rfc_2782 : bool = False ,
135131):
@@ -167,6 +163,8 @@ def url(
167163 URL string may contain port number.
168164 simple_host:
169165 URL string maybe only hyphens and alpha-numerals.
166+ strict_query:
167+ Fail validation on query string parsing error.
170168 rfc_1034:
171169 Allow trailing dot in domain/host name.
172170 Ref: [RFC 1034](https://www.rfc-editor.org/rfc/rfc1034).
@@ -214,5 +212,5 @@ def url(
214212 rfc_1034 ,
215213 rfc_2782 ,
216214 )
217- and _validate_optionals (path , query , fragment )
215+ and _validate_optionals (path , query , fragment , strict_query )
218216 )
0 commit comments