Path: blob/trunk/py/selenium/webdriver/common/bidi/storage.py
4014 views
# Licensed to the Software Freedom Conservancy (SFC) under one1# or more contributor license agreements. See the NOTICE file2# distributed with this work for additional information3# regarding copyright ownership. The SFC licenses this file4# to you under the Apache License, Version 2.0 (the5# "License"); you may not use this file except in compliance6# with the License. You may obtain a copy of the License at7#8# http://www.apache.org/licenses/LICENSE-2.09#10# Unless required by applicable law or agreed to in writing,11# software distributed under the License is distributed on an12# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY13# KIND, either express or implied. See the License for the14# specific language governing permissions and limitations15# under the License.16from __future__ import annotations1718from typing import TYPE_CHECKING, Any1920from selenium.webdriver.common.bidi.common import command_builder2122if TYPE_CHECKING:23from selenium.webdriver.remote.websocket_connection import WebSocketConnection242526class SameSite:27"""Represents the possible same site values for cookies."""2829STRICT = "strict"30LAX = "lax"31NONE = "none"32DEFAULT = "default"333435class BytesValue:36"""Represents a bytes value."""3738TYPE_BASE64 = "base64"39TYPE_STRING = "string"4041def __init__(self, type: str, value: str):42self.type = type43self.value = value4445def to_dict(self) -> dict[str, str]:46"""Converts the BytesValue to a dictionary.4748Returns:49A dictionary representation of the BytesValue.50"""51return {"type": self.type, "value": self.value}525354class Cookie:55"""Represents a cookie."""5657def __init__(58self,59name: str,60value: BytesValue,61domain: str,62path: str | None = None,63size: int | None = None,64http_only: bool | None = None,65secure: bool | None = None,66same_site: str | None = None,67expiry: int | None = None,68):69self.name = name70self.value = value71self.domain = domain72self.path = path73self.size = size74self.http_only = http_only75self.secure = secure76self.same_site = same_site77self.expiry = expiry7879@classmethod80def from_dict(cls, data: dict[str, Any]) -> Cookie:81"""Creates a Cookie instance from a dictionary.8283Args:84data: A dictionary containing the cookie information.8586Returns:87A new instance of Cookie.88"""89# Validation for empty strings90name = data.get("name")91if not name:92raise ValueError("name is required and cannot be empty")93domain = data.get("domain")94if not domain:95raise ValueError("domain is required and cannot be empty")9697value = BytesValue(data.get("value", {}).get("type"), data.get("value", {}).get("value"))98return cls(99name=str(name),100value=value,101domain=str(domain),102path=data.get("path"),103size=data.get("size"),104http_only=data.get("httpOnly"),105secure=data.get("secure"),106same_site=data.get("sameSite"),107expiry=data.get("expiry"),108)109110111class CookieFilter:112"""Represents a filter for cookies."""113114def __init__(115self,116name: str | None = None,117value: BytesValue | None = None,118domain: str | None = None,119path: str | None = None,120size: int | None = None,121http_only: bool | None = None,122secure: bool | None = None,123same_site: str | None = None,124expiry: int | None = None,125):126self.name = name127self.value = value128self.domain = domain129self.path = path130self.size = size131self.http_only = http_only132self.secure = secure133self.same_site = same_site134self.expiry = expiry135136def to_dict(self) -> dict[str, Any]:137"""Converts the CookieFilter to a dictionary.138139Returns:140A dictionary representation of the CookieFilter.141"""142result: dict[str, Any] = {}143if self.name is not None:144result["name"] = self.name145if self.value is not None:146result["value"] = self.value.to_dict()147if self.domain is not None:148result["domain"] = self.domain149if self.path is not None:150result["path"] = self.path151if self.size is not None:152result["size"] = self.size153if self.http_only is not None:154result["httpOnly"] = self.http_only155if self.secure is not None:156result["secure"] = self.secure157if self.same_site is not None:158result["sameSite"] = self.same_site159if self.expiry is not None:160result["expiry"] = self.expiry161return result162163164class PartitionKey:165"""Represents a storage partition key."""166167def __init__(self, user_context: str | None = None, source_origin: str | None = None):168self.user_context = user_context169self.source_origin = source_origin170171@classmethod172def from_dict(cls, data: dict[str, Any]) -> PartitionKey:173"""Creates a PartitionKey instance from a dictionary.174175Args:176data: A dictionary containing the partition key information.177178Returns:179A new instance of PartitionKey.180"""181return cls(182user_context=data.get("userContext"),183source_origin=data.get("sourceOrigin"),184)185186187class BrowsingContextPartitionDescriptor:188"""Represents a browsing context partition descriptor."""189190def __init__(self, context: str):191self.type = "context"192self.context = context193194def to_dict(self) -> dict[str, str]:195"""Converts the BrowsingContextPartitionDescriptor to a dictionary.196197Returns:198Dict: A dictionary representation of the BrowsingContextPartitionDescriptor.199"""200return {"type": self.type, "context": self.context}201202203class StorageKeyPartitionDescriptor:204"""Represents a storage key partition descriptor."""205206def __init__(self, user_context: str | None = None, source_origin: str | None = None):207self.type = "storageKey"208self.user_context = user_context209self.source_origin = source_origin210211def to_dict(self) -> dict[str, str]:212"""Converts the StorageKeyPartitionDescriptor to a dictionary.213214Returns:215Dict: A dictionary representation of the StorageKeyPartitionDescriptor.216"""217result = {"type": self.type}218if self.user_context is not None:219result["userContext"] = self.user_context220if self.source_origin is not None:221result["sourceOrigin"] = self.source_origin222return result223224225class PartialCookie:226"""Represents a partial cookie for setting."""227228def __init__(229self,230name: str,231value: BytesValue,232domain: str,233path: str | None = None,234http_only: bool | None = None,235secure: bool | None = None,236same_site: str | None = None,237expiry: int | None = None,238):239self.name = name240self.value = value241self.domain = domain242self.path = path243self.http_only = http_only244self.secure = secure245self.same_site = same_site246self.expiry = expiry247248def to_dict(self) -> dict[str, Any]:249"""Converts the PartialCookie to a dictionary.250251Returns:252-------253Dict: A dictionary representation of the PartialCookie.254"""255result: dict[str, Any] = {256"name": self.name,257"value": self.value.to_dict(),258"domain": self.domain,259}260if self.path is not None:261result["path"] = self.path262if self.http_only is not None:263result["httpOnly"] = self.http_only264if self.secure is not None:265result["secure"] = self.secure266if self.same_site is not None:267result["sameSite"] = self.same_site268if self.expiry is not None:269result["expiry"] = self.expiry270return result271272273class GetCookiesResult:274"""Represents the result of a getCookies command."""275276def __init__(self, cookies: list[Cookie], partition_key: PartitionKey):277self.cookies = cookies278self.partition_key = partition_key279280@classmethod281def from_dict(cls, data: dict[str, Any]) -> GetCookiesResult:282"""Creates a GetCookiesResult instance from a dictionary.283284Args:285data: A dictionary containing the get cookies result information.286287Returns:288A new instance of GetCookiesResult.289"""290cookies = [Cookie.from_dict(cookie) for cookie in data.get("cookies", [])]291partition_key = PartitionKey.from_dict(data.get("partitionKey", {}))292return cls(cookies=cookies, partition_key=partition_key)293294295class SetCookieResult:296"""Represents the result of a setCookie command."""297298def __init__(self, partition_key: PartitionKey):299self.partition_key = partition_key300301@classmethod302def from_dict(cls, data: dict[str, Any]) -> SetCookieResult:303"""Creates a SetCookieResult instance from a dictionary.304305Args:306data: A dictionary containing the set cookie result information.307308Returns:309A new instance of SetCookieResult.310"""311partition_key = PartitionKey.from_dict(data.get("partitionKey", {}))312return cls(partition_key=partition_key)313314315class DeleteCookiesResult:316"""Represents the result of a deleteCookies command."""317318def __init__(self, partition_key: PartitionKey):319self.partition_key = partition_key320321@classmethod322def from_dict(cls, data: dict[str, Any]) -> DeleteCookiesResult:323"""Creates a DeleteCookiesResult instance from a dictionary.324325Args:326data: A dictionary containing the delete cookies result information.327328Returns:329A new instance of DeleteCookiesResult.330"""331partition_key = PartitionKey.from_dict(data.get("partitionKey", {}))332return cls(partition_key=partition_key)333334335class Storage:336"""BiDi implementation of the storage module."""337338def __init__(self, conn: WebSocketConnection) -> None:339self.conn = conn340341def get_cookies(342self,343filter: CookieFilter | None = None,344partition: BrowsingContextPartitionDescriptor | StorageKeyPartitionDescriptor | None = None,345) -> GetCookiesResult:346"""Gets cookies matching the specified filter.347348Args:349filter: Optional filter to specify which cookies to retrieve.350partition: Optional partition key to limit the scope of the operation.351352Returns:353A GetCookiesResult containing the cookies and partition key.354355Example:356result = await storage.get_cookies(357filter=CookieFilter(name="sessionId"),358partition=PartitionKey(...)359)360"""361params = {}362if filter is not None:363params["filter"] = filter.to_dict()364if partition is not None:365params["partition"] = partition.to_dict()366367result = self.conn.execute(command_builder("storage.getCookies", params))368return GetCookiesResult.from_dict(result)369370def set_cookie(371self,372cookie: PartialCookie,373partition: BrowsingContextPartitionDescriptor | StorageKeyPartitionDescriptor | None = None,374) -> SetCookieResult:375"""Sets a cookie in the browser.376377Args:378cookie: The cookie to set.379partition: Optional partition descriptor.380381Returns:382The result of the set cookie command.383"""384params = {"cookie": cookie.to_dict()}385if partition is not None:386params["partition"] = partition.to_dict()387388result = self.conn.execute(command_builder("storage.setCookie", params))389return SetCookieResult.from_dict(result)390391def delete_cookies(392self,393filter: CookieFilter | None = None,394partition: BrowsingContextPartitionDescriptor | StorageKeyPartitionDescriptor | None = None,395) -> DeleteCookiesResult:396"""Deletes cookies that match the given parameters.397398Args:399filter: Optional filter to match cookies to delete.400partition: Optional partition descriptor.401402Returns:403The result of the delete cookies command.404"""405params = {}406if filter is not None:407params["filter"] = filter.to_dict()408if partition is not None:409params["partition"] = partition.to_dict()410411result = self.conn.execute(command_builder("storage.deleteCookies", params))412return DeleteCookiesResult.from_dict(result)413414415