@app.route('/register',methods=['POST']) defregister(): if request.data: try: ifnot check(request.data): return"Register Failed" data = json.loads(request.data) if"username"notin data or"password"notin data: return"Register Failed" User = user() merge(data, User) Users.append(User) except Exception: return"Register Failed" return"Register Success" else: return"Register Failed"
@app.route('/login',methods=['POST']) deflogin(): if request.data: try: data = json.loads(request.data) if"username"notin data or"password"notin data: return"Login Failed" for user in Users: if user.check(data): session["username"] = data["username"] return"Login Success" except Exception: return"Login Failed" return"Login Failed"
defparse_cookie(raw: str) -> Dict[str, List[str]]: """Parses a raw cookie string into a dictionary. The function takes a raw cookie string (usually from HTTP headers) and returns a dictionary where each key is a cookie name and the value is a list of values for that cookie. The function handles quoted values and skips invalid cookie names. Args: raw (str): The raw cookie string to be parsed. Returns: Dict[str, List[str]]: A dictionary containing the cookie names as keys and a list of values for each cookie. Example: ```python raw = 'name1=value1; name2="value2"; name3=value3' cookies = parse_cookie(raw) # cookies will be {'name1': ['value1'], 'name2': ['value2'], 'name3': ['value3']}
""" # noqa: E501
cookies: Dict[str, List[str]] = {}
for token in raw.split(";"):
name, sep, value = token.partition("=")
name = name.strip()
value = value.strip()
# Support cookies =value or plain value with no name
# https://github.com/httpwg/http-extensions/issues/159
if not sep:
if not name:
# Empty value like ;; or a cookie header with no value
continue
name, value = "", name
if COOKIE_NAME_RESERVED_CHARS.search(name): # no cov
continue
if len(value) > 2 and value[0] == '"' and value[-1] == '"': # no cov
value = _unquote(value)
if name in cookies:
cookies[name].append(value)
else:
cookies[name] = [value]
return cookies
1 2 3 4 5 6 7 8
这里有一点需要注意:
```python for token in raw.split(";"): name, sep, value = token.partition("=") name = name.strip() value = value.strip()
这个代码很显然是将分号前后分割成了两个字符串,也就是说,我们想要输入的 Cookie: user=adm;n 会变成 user=adm 以及 n 这两个串。
根据这几行,大概可以发现最后返回的内容和什么有关了:
1 2 3 4 5 6 7 8 9
iflen(value) > 2and value[0] == '"'and value[-1] == '"': # no cov value = _unquote(value)
if name in cookies: cookies[name].append(value) else: cookies[name] = [value]
return cookies
很明显,最终返回的是 cookies ,但是每次操作 cookies 都是增加的 value 参数,由此,根据 value = _unquote(value) ,这里跟进 _unquote(value) :
然而,恭喜了,每过,被 forbidden 了。回去看看,破案了,admin 路由函数中存在这么一个比较: if key and value and type(key) is str and '_.' not in key: ,这个就卡住我了。先来看下这几行:
1 2 3 4 5
key = request.json['key'] value = request.json['value'] if key and value andtype(key) isstrand'_.'notin key: pollute = Pollute() pydash.set_(pollute, key, value)
defset_(obj, path, value): """ Sets the value of an object described by `path`. If any part of the object path doesn't exist, it will be created. Args: obj (list|dict): Object to modify. path (str | list): Target path to set value to. value (mixed): Value to set. Returns: mixed: Modified `obj`. Warning: `obj` is modified in place. Example: >>> set_({}, 'a.b.c', 1) {'a': {'b': {'c': 1}}} >>> set_({}, 'a.0.c', 1) {'a': {'0': {'c': 1}}} >>> set_([1, 2], '[2][0]', 1) [1, 2, [1]] >>> set_({}, 'a.b[0].c', 1) {'a': {'b': [{'c': 1}]}} .. versionadded:: 2.2.0 .. versionchanged:: 3.3.0 Added :func:`set_` as main definition and :func:`deep_set` as alias. .. versionchanged:: 4.0.0 - Modify `obj` in place. - Support creating default path values as ``list`` or ``dict`` based on whether key or index substrings are used. - Remove alias ``deep_set``. """ return set_with(obj, path, value)
defset_with(obj, path, value, customizer=None): """ This method is like :func:`set_` except that it accepts customizer which is invoked to produce the objects of path. If customizer returns undefined path creation is handled by the method instead. The customizer is invoked with three arguments: ``(nested_value, key, nested_object)``. Args: obj (list|dict): Object to modify. path (str | list): Target path to set value to. value (mixed): Value to set. customizer (callable, optional): The function to customize assigned values. Returns: mixed: Modified `obj`. Warning: `obj` is modified in place. Example: >>> set_with({}, '[0][1]', 'a', lambda: {}) {0: {1: 'a'}} .. versionadded:: 4.0.0 .. versionchanged:: 4.3.1 Fixed bug where a callable `value` was called when being set. """ return update_with(obj, path, pyd.constant(value), customizer=customizer)
defupdate_with(obj, path, updater, customizer=None): # noqa: C901 """ This method is like :func:`update` except that it accepts customizer which is invoked to produce the objects of path. If customizer returns ``None``, path creation is handled by the method instead. The customizer is invoked with three arguments: ``(nested_value, key, nested_object)``. Args: obj (list|dict): Object to modify. path (str|list): A string or list of keys that describe the object path to modify. updater (callable): Function that returns updated value. customizer (callable, optional): The function to customize assigned values. Returns: mixed: Updated `obj`. Warning: `obj` is modified in place. Example: >>> update_with({}, '[0][1]', lambda: 'a', lambda: {}) {0: {1: 'a'}} .. versionadded:: 4.0.0 """ ifnotcallable(updater): updater = pyd.constant(updater)
defto_path_tokens(value): """Parse `value` into :class:`PathToken` objects.""" if pyd.is_string(value) and ("."in value or"["in value): # Since we can't tell whether a bare number is supposed to be dict key or a list index, we # support a special syntax where any string-integer surrounded by brackets is treated as a # list index and converted to an integer. keys = [ PathToken(int(key[1:-1]), default_factory=list) if RE_PATH_LIST_INDEX.match(key) else PathToken(unescape_path_key(key), default_factory=dict) for key infilter(None, RE_PATH_KEY_DELIM.split(value)) ] elif pyd.is_string(value) or pyd.is_number(value): keys = [PathToken(value, default_factory=dict)] elif value is UNSET: keys = [] else: keys = value
defstatic( self, uri: str, file_or_directory: Union[PathLike, str], pattern: str = r"/?.+", use_modified_since: bool = True, use_content_range: bool = False, stream_large_files: Union[bool, int] = False, name: str = "static", host: Optional[str] = None, strict_slashes: Optional[bool] = None, content_type: Optional[str] = None, apply: bool = True, resource_type: Optional[str] = None, index: Optional[Union[str, Sequence[str]]] = None, directory_view: bool = False, directory_handler: Optional[DirectoryHandler] = None, ): """Register a root to serve files from. The input can either be a file or a directory. This method provides an easy and simple way to set up the route necessary to serve static files. Args: uri (str): URL path to be used for serving static content. file_or_directory (Union[PathLike, str]): Path to the static file or directory with static files. pattern (str, optional): Regex pattern identifying the valid static files. Defaults to `r"/?.+"`. use_modified_since (bool, optional): If true, send file modified time, and return not modified if the browser's matches the server's. Defaults to `True`. use_content_range (bool, optional): If true, process header for range requests and sends the file part that is requested. Defaults to `False`. stream_large_files (Union[bool, int], optional): If `True`, use the `StreamingHTTPResponse.file_stream` handler rather than the `HTTPResponse.file handler` to send the file. If this is an integer, it represents the threshold size to switch to `StreamingHTTPResponse.file_stream`. Defaults to `False`, which means that the response will not be streamed. name (str, optional): User-defined name used for url_for. Defaults to `"static"`. host (Optional[str], optional): Host IP or FQDN for the service to use. strict_slashes (Optional[bool], optional): Instruct Sanic to check if the request URLs need to terminate with a slash. content_type (Optional[str], optional): User-defined content type for header. apply (bool, optional): If true, will register the route immediately. Defaults to `True`. resource_type (Optional[str], optional): Explicitly declare a resource to be a `"file"` or a `"dir"`. index (Optional[Union[str, Sequence[str]]], optional): When exposing against a directory, index is the name that will be served as the default file. When multiple file names are passed, then they will be tried in order. directory_view (bool, optional): Whether to fallback to showing the directory viewer when exposing a directory. Defaults to `False`. directory_handler (Optional[DirectoryHandler], optional): An instance of DirectoryHandler that can be used for explicitly controlling and subclassing the behavior of the default directory handler. Returns: List[sanic.router.Route]: Routes registered on the router. Examples: Serving a single file: ```python app.static('/foo', 'path/to/static/file.txt')
""" # noqa: E501
name = self.generate_name(name)
if strict_slashes is None and self.strict_slashes is not None:
strict_slashes = self.strict_slashes
if not isinstance(file_or_directory, (str, bytes, PurePath)):
raise ValueError(
f"Static route must be a valid path, not {file_or_directory}"
)
try:
file_or_directory = Path(file_or_directory).resolve()
except TypeError:
raise TypeError(
"Static file or directory must be a path-like object or string"
)
if directory_handler and (directory_view or index):
raise ValueError(
"When explicitly setting directory_handler, you cannot "
"set either directory_view or index. Instead, pass "
"these arguments to your DirectoryHandler instance."
)
if not directory_handler:
directory_handler = DirectoryHandler(
uri=uri,
directory=file_or_directory,
directory_view=directory_view,
index=index,
)
static = FutureStatic(
uri,
file_or_directory,
pattern,
use_modified_since,
use_content_range,
stream_large_files,
name,
host,
strict_slashes,
content_type,
resource_type,
directory_handler,
)
self._future_statics.add(static)
if apply:
self._apply_static(static)
1 2 3 4 5 6 7 8 9 10 11
注释里面存在这两句话:
```tex directory_view (bool, optional): Whether to fallback to showing the directory viewer when exposing a directory. Defaults to `False`. directory_handler (Optional[DirectoryHandler], optional): An instance of DirectoryHandler that can be used for explicitly controlling and subclassing the behavior of the default directory handler.
defcreate_log_dir(n): ret = "" for i inrange(n): num = random.randint(0, 9) letter = chr(random.randint(97, 122)) Letter = chr(random.randint(65, 90)) s = str(random.choice([num, letter, Letter])) ret += s return ret app = Sanic(__name__) app.static("/static/", "./static/")
@app.route("/Wa58a1qEQ59857qQRPPQ") asyncdefsecret(request): withopen("/h111int",'r') as f: hint=f.read() return text(hint)
defmerge(src, dst): for k, v in src.items(): ifhasattr(dst, '__getitem__'): if dst.get(k) andtype(v) == dict: merge(v, dst.get(k)) else: dst[k] = v elifhasattr(dst, k) andtype(v) == dict: merge(v, getattr(dst, k)) else: setattr(dst, k, v)
a = {"a":"1","b":"2","c":"c"} c = {"c":"3"}
merge(a,c) print(c)
最开始的时候,k,v 分别获取了 a 和 1 这两个字符,然后继续向后执行,当函数执行到 if hasattr(dst, '__getitem__'): 的时候,如果发现有 __getitem__ 属性,则大致判断这个是个字典,执行下一步,如果没有,则判断目标字典里是否存在 a 这一个属性,以及是否为字典,如果是字典,则递归调用,如果不是字典,则执行 else 里面的语句,设置一个全新的属性在后面。在这里因为目标字典只有 c 字段,但是源对象是一个字典,所以会进入 if,进而设置一个新的属性,也就是成功加进去了。
if dst.get(k) and type(v) == dict: 这一行,检查目标字典的 k 键,也就是第一次进入时迭代获取到的 a 属性,目标是确认 a 属性是否有值,同时判断 k 是否为字典,如果 k 是字典,就递归执行。
defset_(obj, path, value): """ Sets the value of an object described by `path`. If any part of the object path doesn't exist, it will be created. 设置由“path”描述的对象的值。如果对象路径的任何部分不存在,它将被创建。(这里稍微有点类似于flask的ssti里面找链子的方式。) Args: obj (list|dict): Object to modify. path (str | list): Target path to set value to. value (mixed): Value to set. Returns: mixed: Modified `obj`. Warning: `obj` is modified in place. Example: >>> set_({}, 'a.b.c', 1) {'a': {'b': {'c': 1}}} >>> set_({}, 'a.0.c', 1) {'a': {'0': {'c': 1}}} >>> set_([1, 2], '[2][0]', 1) [1, 2, [1]] >>> set_({}, 'a.b[0].c', 1) {'a': {'b': [{'c': 1}]}} .. versionadded:: 2.2.0 .. versionchanged:: 3.3.0 Added :func:`set_` as main definition and :func:`deep_set` as alias. .. versionchanged:: 4.0.0 - Modify `obj` in place. - Support creating default path values as ``list`` or ``dict`` based on whether key or index substrings are used. - Remove alias ``deep_set``. """ return set_with(obj, path, value)
defset_with(obj, path, value, customizer=None): """ This method is like :func:`set_` except that it accepts customizer which is invoked to produce the objects of path. If customizer returns undefined path creation is handled by the method instead. The customizer is invoked with three arguments: ``(nested_value, key, nested_object)``. 这个方法类似于:func:`set_`,除了它接受定制器,调用customizer生成路径的对象。如果customizer返回未定义的路径,则由该方法处理路径创建 相反。使用三个参数调用customizer:`(nested_value、key、nested_object)`` Args: obj (list|dict): Object to modify. path (str | list): Target path to set value to. value (mixed): Value to set. customizer (callable, optional): The function to customize assigned values. Returns: mixed: Modified `obj`. Warning: `obj` is modified in place. Example: >>> set_with({}, '[0][1]', 'a', lambda: {}) {0: {1: 'a'}} .. versionadded:: 4.0.0 .. versionchanged:: 4.3.1 Fixed bug where a callable `value` was called when being set. """ return update_with(obj, path, pyd.constant(value), customizer=customizer)
defupdate_with(obj, path, updater, customizer=None): # noqa: C901 """ This method is like :func:`update` except that it accepts customizer which is invoked to produce the objects of path. If customizer returns ``None``, path creation is handled by the method instead. The customizer is invoked with three arguments: ``(nested_value, key, nested_object)``. Args: obj (list|dict): Object to modify. path (str|list): A string or list of keys that describe the object path to modify. updater (callable): Function that returns updated value. customizer (callable, optional): The function to customize assigned values. 这个方法类似于:func:`update`,除了它接受定制器,调用定制器生成 路径的对象。如果定制器返回“None”,则路径创建由以下方法处理 相反。使用三个参数调用定制器:“(nested_value,key,nested_object)”。 Returns: mixed: Updated `obj`. Warning: `obj` is modified in place. Example: >>> update_with({}, '[0][1]', lambda: 'a', lambda: {}) {0: {1: 'a'}} .. versionadded:: 4.0.0 """ ifnotcallable(updater): updater = pyd.constant(updater)
defto_path_tokens(value): """Parse `value` into :class:`PathToken` objects.""" if pyd.is_string(value) and ("."in value or"["in value): # Since we can't tell whether a bare number is supposed to be dict key or a list index, we # support a special syntax where any string-integer surrounded by brackets is treated as a # list index and converted to an integer. #由于我们无法判断一个空数应该是字典键还是列表索引,我们 #支持一种特殊语法,其中任何被括号括起来的字符串整数都被视为 #列表索引并转换为整数。 keys = [ #使用正则表达式 RE_PATH_KEY_DELIM来分割字符串。分割后,对于每个部分(key),会进一步检查: PathToken(int(key[1:-1]), default_factory=list) #如果 key 匹配 RE_PATH_LIST_INDEX,则将该部分视为列表索引,并创建一个 PathToken 对象,其键为转换后的整数索引,默认值生成器为 list。 if RE_PATH_LIST_INDEX.match(key) else PathToken(unescape_path_key(key), default_factory=dict) for key infilter(None, RE_PATH_KEY_DELIM.split(value)) ] #如果 key 不匹配 RE_PATH_LIST_INDEX,则将其视为字典键,并通过 unescape_path_key(未在代码段中定义,但我们可以假设它用于处理可能的转义字符)函数处理后,创建一个 PathToken 对象,其键为处理后的字符串,默认值生成器为 dict。 elif pyd.is_string(value) or pyd.is_number(value): keys = [PathToken(value, default_factory=dict)] #如果 value 是 UNSET则返回一个空的 PathToken 列表。 elif value is UNSET: keys = [] #如果 value 不是上述任何一种情况(即它可能已经是一个列表或类似结构),则直接返回 value(尽管这里可能存在一个类型不匹配的问题,因为通常我们期望返回的是 PathToken 对象的列表,而不是原始值)。然而,基于函数的命名和描述,这可能是一个错误或特殊情况的处理方式。 else: keys = value