mirror of https://github.com/dnomd343/ProxyC
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
103 lines
3.0 KiB
103 lines
3.0 KiB
#!/usr/bin/python
|
|
# -*- coding:utf-8 -*-
|
|
|
|
import re
|
|
import base64
|
|
import urllib.parse
|
|
|
|
|
|
def urlEncode(content: str) -> str or None: # url-encode
|
|
try:
|
|
return urllib.parse.urlencode(content)
|
|
except:
|
|
return None
|
|
|
|
|
|
def urlDecode(content: str) -> str or None: # url-decode
|
|
try:
|
|
return urllib.parse.unquote(content)
|
|
except:
|
|
return None
|
|
|
|
|
|
def base64Encode(content: str, urlSafe: bool = False, isPadding: bool = True) -> str or None:
|
|
try:
|
|
content = base64.b64encode(content.encode()).decode()
|
|
if urlSafe:
|
|
content = content.replace('+', '-')
|
|
content = content.replace('/', '_')
|
|
if not isPadding:
|
|
content = content.replace('=', '')
|
|
return content
|
|
except:
|
|
return None
|
|
|
|
|
|
def base64Decode(content: str) -> str or None:
|
|
try:
|
|
content = content.replace('-', '+').replace('_', '/')
|
|
if len(content) % 4 in range(2, 4): # remainder -> 2 or 3
|
|
content = content.ljust((len(content) // 4 + 1) * 4, '=') # increase to 4n
|
|
return base64.b64decode(content).decode()
|
|
except:
|
|
return None
|
|
|
|
|
|
def formatHost(host: str) -> str: # host -> IP / Domain
|
|
try:
|
|
host = host.lower().strip()
|
|
if host[:1] == '[' and host[-1:] == ']': # [IPv6]
|
|
return host[1:-1]
|
|
except:
|
|
pass
|
|
return host
|
|
|
|
|
|
def paramSplit(paramStr: str) -> dict: # ?param_1=xxx¶m_2=xxx¶m_3=xxx
|
|
if paramStr.startswith('?'):
|
|
paramStr = paramStr[1:] # remove `?` char
|
|
params = {}
|
|
for field in paramStr.split('&'):
|
|
if field.find('=') < 0: # without `=` char
|
|
continue
|
|
key, value = field.split('=', maxsplit = 1)
|
|
params[key] = urlDecode(value)
|
|
return params
|
|
|
|
|
|
def splitEdParam(path: str) -> tuple[int or None, str]: # split early-data option
|
|
if path.find('?') == -1:
|
|
return None, path
|
|
content = re.search(r'^([\s\S]*?)\?([\s\S]*)$', path)
|
|
ed = None
|
|
params = []
|
|
for field in content[2].split('&'): # ?param_a=...¶m_b=...
|
|
if not field.startswith('ed='):
|
|
params.append(field)
|
|
continue
|
|
ed = int(field[3:]) # ed=...
|
|
if ed is None: # ed param not found
|
|
return None, path
|
|
if not params: # param -> []
|
|
return ed, content[1]
|
|
return ed, content[1] + '?' + '&'.join(params)
|
|
|
|
|
|
def urlSplit(url: str) -> dict: # scheme://[auth@]server[:port]/.../...?param_1=...¶m_2=...#remark
|
|
url = urllib.parse.urlparse(url)
|
|
auth = port = None
|
|
netloc = url[1]
|
|
if not netloc.find(':') < 0: # server[:port]
|
|
netloc, port = netloc.rsplit(':', maxsplit = 1)
|
|
port = int(port)
|
|
if not netloc.find('@') < 0: # [auth@]server
|
|
auth, netloc = netloc.rsplit('@', maxsplit = 1)
|
|
return {
|
|
'scheme': url[0],
|
|
'auth': auth,
|
|
'server': formatHost(netloc),
|
|
'port': port,
|
|
'path': url[2],
|
|
'params': paramSplit(url[4]),
|
|
'remark': urlDecode(url[5])
|
|
}
|
|
|