def unquote(s): s = _unquote(s) # PY3 always returns unicode. PY2 seems to always return what you give it, # which differs from quote's behavior. Just to be safe, make sure it is # unicode before we return. if isinstance(s, bytes): s = s.decode('utf-8') return s
def parse_options_header(value, multiple=False): """Parse a ``Content-Type`` like header into a tuple with the content type and the options: >>> parse_options_header('text/html; charset=utf8') ('text/html', {'charset': 'utf8'}) This should not be used to parse ``Cache-Control`` like headers that use a slightly different format. For these headers use the :func:`parse_dict_header` function. .. versionadded:: 0.5 :param value: the header to parse. :param multiple: Whether try to parse and return multiple MIME types :return: (mimetype, options) or (mimetype, options, mimetype, options, …) if multiple=True """ if not value: return '', {} result = [] value = "," + value.replace("\n", ",") while value: match = _option_header_start_mime_type.match(value) if not match: break result.append(match.group(1)) # mimetype options = {} # Parse options rest = match.group(2) while rest: optmatch = _option_header_piece_re.match(rest) if not optmatch: break option, encoding, _, option_value = optmatch.groups() option = unquote_header_value(option) if option_value is not None: option_value = unquote_header_value( option_value, option == 'filename') if encoding is not None: option_value = _unquote(option_value).decode(encoding) options[option] = option_value rest = rest[optmatch.end():] result.append(options) if multiple is False: return tuple(result) value = rest return tuple(result) if result else ('', {})
def create_uri(self, redirect_uri, state): description = _unquote(self.description) # See: # http://openid.net/specs/openid-connect-core-1_0.html#ImplicitAuthError hash_or_question = "#" if self.grant_type == "implicit" else "?" uri = "{0}{1}error={2}&error_description={3}".format( redirect_uri, hash_or_question, self.error, description) # Add state if present. uri = uri + ("&state={0}".format(state) if state else "") return uri
def _extract_credentials(url): """Extract authentication (user name and password) credentials from the given URL. >>> extract_credentials('http://*****:*****@localhost:5984/_config/') ('http://*****:*****@localhost:5984/_config/') ('http://*****:*****@example.com', 'secret')) """ parts = urlsplit(url) netloc = parts[1] if '@' in netloc: creds, netloc = netloc.split('@') credentials = tuple(_unquote(i) for i in creds.split(':')) parts = list(parts) parts[1] = netloc else: credentials = None return urlunsplit(parts), credentials
def _extract_credentials(url): """ Extract authentication (user name and password) credentials from the given URL. >>> extract_credentials('http://*****:*****@localhost:5984/_config/') ('http://*****:*****@localhost:5984/_config/') ('http://*****:*****@example.com', 'secret')) """ parts = urlsplit(url) netloc = parts[1] if '@' in netloc: creds, netloc = netloc.split('@') credentials = tuple(_unquote(i) for i in creds.split(':')) parts = list(parts) parts[1] = netloc else: credentials = None return urlunsplit(parts), credentials
def parse_options_header(value, multiple=False): """Parse a ``Content-Type`` like header into a tuple with the content type and the options: >>> parse_options_header('text/html; charset=utf8') ('text/html', {'charset': 'utf8'}) This should not be used to parse ``Cache-Control`` like headers that use a slightly different format. For these headers use the :func:`parse_dict_header` function. .. versionchanged:: 0.15 :rfc:`2231` parameter continuations are handled. .. versionadded:: 0.5 :param value: the header to parse. :param multiple: Whether try to parse and return multiple MIME types :return: (mimetype, options) or (mimetype, options, mimetype, options, …) if multiple=True """ if not value: return "", {} result = [] value = "," + value.replace("\n", ",") while value: match = _option_header_start_mime_type.match(value) if not match: break result.append(match.group(1)) # mimetype options = {} # Parse options rest = match.group(2) continued_encoding = None while rest: optmatch = _option_header_piece_re.match(rest) if not optmatch: break option, count, encoding, language, option_value = optmatch.groups() # Continuations don't have to supply the encoding after the # first line. If we're in a continuation, track the current # encoding to use for subsequent lines. Reset it when the # continuation ends. if not count: continued_encoding = None else: if not encoding: encoding = continued_encoding continued_encoding = encoding option = unquote_header_value(option) if option_value is not None: option_value = unquote_header_value(option_value, option == "filename") if encoding is not None: option_value = _unquote(option_value).decode(encoding) if count: # Continuations append to the existing value. For # simplicity, this ignores the possibility of # out-of-order indices, which shouldn't happen anyway. options[option] = options.get(option, "") + option_value else: options[option] = option_value rest = rest[optmatch.end() :] result.append(options) if multiple is False: return tuple(result) value = rest return tuple(result) if result else ("", {})
def run_viewvc(self): """Run ViewVC to field a single request.""" ### Much of this is adapter from Python's standard library ### module CGIHTTPServer. # Is this request even aimed at ViewVC? If not, complain. if not self.is_viewvc(): raise NotViewVCLocationException() # If htpasswd authentication is enabled, try to authenticate the user. self.username = None if options.htpasswd_file: authn = self.headers.get('authorization') if not authn: raise AuthenticationException() try: kind, data = authn.split(' ', 1) if kind == 'Basic': data = base64.b64decode(data) username, password = data.split(':', 1) except: raise AuthenticationException() if not self.validate_password(options.htpasswd_file, username, password): raise AuthenticationException() self.username = username # Setup the environment in preparation of executing ViewVC's core code. env = os.environ scriptname = options.script_alias and '/' + options.script_alias or '' viewvc_url = self.server.url[:-1] + scriptname rest = self.path[len(scriptname):] i = rest.rfind('?') if i >= 0: rest, query = rest[:i], rest[i + 1:] else: query = '' # Since we're going to modify the env in the parent, provide empty # values to override previously set values for k in env.keys(): if k[:5] == 'HTTP_': del env[k] for k in ('QUERY_STRING', 'REMOTE_HOST', 'CONTENT_LENGTH', 'HTTP_USER_AGENT', 'HTTP_COOKIE'): if k in env: env[k] = "" # XXX Much of the following could be prepared ahead of time! env['SERVER_SOFTWARE'] = self.version_string() env['SERVER_NAME'] = self.server.server_name env['GATEWAY_INTERFACE'] = 'CGI/1.1' env['SERVER_PROTOCOL'] = self.protocol_version env['SERVER_PORT'] = str(self.server.server_port) env['REQUEST_METHOD'] = self.command uqrest = _unquote(rest) env['PATH_INFO'] = uqrest env['SCRIPT_NAME'] = scriptname if query: env['QUERY_STRING'] = query env['HTTP_HOST'] = self.server.address[0] host = self.address_string() if host != self.client_address[0]: env['REMOTE_HOST'] = host env['REMOTE_ADDR'] = self.client_address[0] if self.username: env['REMOTE_USER'] = self.username env['CONTENT_TYPE'] = self.headers.get_content_type() length = self.headers.get('content-length', None) if length: env['CONTENT_LENGTH'] = length accept = [] for line in self.headers.getallmatchingheaders('accept'): if line[:1] in string.whitespace: accept.append(line.strip()) else: accept = accept + line[7:].split(',') env['HTTP_ACCEPT'] = ','.join(accept) ua = self.headers.get('user-agent', None) if ua: env['HTTP_USER_AGENT'] = ua modified = self.headers.get('if-modified-since', None) if modified: env['HTTP_IF_MODIFIED_SINCE'] = modified etag = self.headers.get('if-none-match', None) if etag: env['HTTP_IF_NONE_MATCH'] = etag # AUTH_TYPE # REMOTE_IDENT # XXX Other HTTP_* headers try: try: viewvc.main(StandaloneServer(self), cfg) finally: if not self.wfile.closed: self.wfile.flush() except SystemExit as status: self.log_error("ViewVC exit status %s", str(status)) else: self.log_error("ViewVC exited ok")
def unquote(s): if isinstance(s, bytes): s = s.decode("ascii") quoted = _unquote(s) return quoted.encode("ascii")
def unquote(s): return to_unicode(_unquote(s))
def uri_path(uri: str, unquote: bool = False) -> PurePosixPath: raw = urlsplit(uri).path path = _unquote(raw) if unquote else raw return PurePosixPath(path)
# coding=utf-8 # Copyright 2013 Elsie Powell - embolalia.com # Licensed under the Eiffel Forum License 2. from sopel import web, tools from sopel.config.types import StaticSection, ValidatedAttribute from sopel.module import NOLIMIT, commands, example, rule import json import re import sys if sys.version_info.major < 3: from urllib.parse import unquote as _unquote unquote = lambda s: _unquote(s.encode('utf-8')).decode('utf-8') else: from urllib.parse import unquote REDIRECT = re.compile(r'^REDIRECT (.*)') class WikipediaSection(StaticSection): default_lang = ValidatedAttribute('default_lang', default='en') """The default language to find articles from.""" lang_per_channel = ValidatedAttribute('lang_per_channel') def setup(bot): bot.config.define_section('wikipedia', WikipediaSection) regex = re.compile('([a-z]+).(wikipedia.org/wiki/)([^ ]+)') if not bot.memory.contains('url_callbacks'):
def parse_options_header(value, multiple=False): """将像``Content-Type``这样的HTTP头部解析成包含内容类型和选项的元组: >>> parse_options_header('text/html; charset=utf8') ('text/html', {'charset': 'utf8'}) 不应该使用这个函数来解析像``Cache-control``这样子稍微使用了不同格式的HTTP头部。对于这 种头部,使用:func:``parse_dict_header``函数。 .. versionchanged:: 0.15 :rfc:`2231` 处理参数连续 .. versionadded:: 0.5 :param value: 要解析的头部。 :param multiple: 尝试解析并且返回多个MIME types :return: (mimetype, options) or (mimetype, options, mimetype, options, …) if multiple=True """ if not value: # value == None or value == "" return "", {} result = [] # value = 'text/html; charset=utf-8' value = "," + value.replace("\n", ",") # ',text/html; charset=utf-8' while value: match = _option_header_start_mime_type.match(value) if not match: break result.append(match.group(1)) # mimetype, text/html(Content-type) options = {} # 解析选项 rest = match.group(2) # ; charset=utf-8 continued_encoding = None while rest: optmatch = _option_header_piece_re.match(rest) if not optmatch: break option, count, encoding, language, option_value = optmatch.groups( ) # ('charset, None, None, None, 'utf-8') # 首行后的连续行不需要提供编码。如果处于连续行,使用当前的编码当作后续行的编码。 # 当连续行结束的时候进行重置。 if not count: continued_encoding = None else: if not encoding: encoding = continued_encoding continued_encoding = encoding option = unquote_header_value(option) if option_value is not None: option_value = unquote_header_value(option_value, option == "filename") if encoding is not None: option_value = _unquote(option_value).decode(encoding) if count: # 连续添加到正存在的的值,为了简洁性,忽略了不该产生的乱许索引的可能性。 options[option] = options.get(option, "") + option_value else: options[option] = option_value rest = rest[optmatch.end():] result.append(options) if multiple is False: return tuple(result) value = rest return tuple(result) if result else ("", {})
def parse_options_header( value: t.Optional[str], multiple: "te.Literal[None]" = None ) -> t.Tuple[str, t.Dict[str, str]]: """Parse a ``Content-Type``-like header into a tuple with the value and any options: >>> parse_options_header('text/html; charset=utf8') ('text/html', {'charset': 'utf8'}) This should is not for ``Cache-Control``-like headers, which use a different format. For those, use :func:`parse_dict_header`. :param value: The header value to parse. .. versionchanged:: 2.1 The ``multiple`` parameter is deprecated and will be removed in Werkzeug 2.2. .. versionchanged:: 0.15 :rfc:`2231` parameter continuations are handled. .. versionadded:: 0.5 """ if multiple is not None: import warnings warnings.warn( "The 'multiple' parameter of 'parse_options_header' is" " deprecated and will be removed in Werkzeug 2.2.", DeprecationWarning, stacklevel=2, ) if not value: return "", {} result: t.List[t.Any] = [] value = "," + value.replace("\n", ",") while value: match = _option_header_start_mime_type.match(value) if not match: break result.append(match.group(1)) # mimetype options: t.Dict[str, str] = {} # Parse options rest = match.group(2) encoding: t.Optional[str] continued_encoding: t.Optional[str] = None while rest: optmatch = _option_header_piece_re.match(rest) if not optmatch: break option, count, encoding, language, option_value = optmatch.groups() # Continuations don't have to supply the encoding after the # first line. If we're in a continuation, track the current # encoding to use for subsequent lines. Reset it when the # continuation ends. if not count: continued_encoding = None else: if not encoding: encoding = continued_encoding continued_encoding = encoding option = unquote_header_value(option) if option_value is not None: option_value = unquote_header_value(option_value, option == "filename") if encoding is not None: option_value = _unquote(option_value).decode(encoding) if count: # Continuations append to the existing value. For # simplicity, this ignores the possibility of # out-of-order indices, which shouldn't happen anyway. if option_value is not None: options[option] = options.get(option, "") + option_value else: options[option] = option_value # type: ignore[assignment] rest = rest[optmatch.end() :] result.append(options) if not multiple: return tuple(result) # type: ignore[return-value] value = rest return tuple(result) if result else ("", {}) # type: ignore[return-value]