@@ -44,9 +44,11 @@ use objc2_core_foundation::CGSize;
4444use objc2_core_foundation:: { CGPoint , CGRect } ;
4545use objc2_foundation:: {
4646 ns_string, MainThreadMarker , NSArray , NSBundle , NSDate , NSError , NSHTTPCookie ,
47- NSHTTPCookieSameSiteLax , NSHTTPCookieSameSiteStrict , NSJSONSerialization , NSMutableURLRequest ,
48- NSNumber , NSObjectNSKeyValueCoding , NSObjectProtocol , NSString , NSUTF8StringEncoding , NSURL ,
49- NSUUID ,
47+ NSHTTPCookieDomain , NSHTTPCookieExpires , NSHTTPCookieMaximumAge , NSHTTPCookieName ,
48+ NSHTTPCookiePath , NSHTTPCookiePropertyKey , NSHTTPCookieSameSiteLax , NSHTTPCookieSameSiteStrict ,
49+ NSHTTPCookieSecure , NSHTTPCookieValue , NSHTTPCookieVersion , NSJSONSerialization ,
50+ NSMutableDictionary , NSMutableURLRequest , NSNumber , NSObjectNSKeyValueCoding , NSObjectProtocol ,
51+ NSString , NSUTF8StringEncoding , NSURL , NSUUID ,
5052} ;
5153#[ cfg( target_os = "ios" ) ]
5254use objc2_ui_kit:: { UIScrollView , UIViewAutoresizing } ;
@@ -979,6 +981,70 @@ r#"Object.defineProperty(window, 'ipc', {
979981 cookie_builder. build ( )
980982 }
981983
984+ unsafe fn cookie_into_wkwebview ( cookie : & cookie:: Cookie < ' _ > ) -> Retained < NSHTTPCookie > {
985+ let nstring_true: & ' static NSString = ns_string ! ( "TRUE" ) ;
986+ let nstring_false: & ' static NSString = ns_string ! ( "FALSE" ) ;
987+ let nstring_0: & ' static NSString = ns_string ! ( "0" ) ;
988+ let nstring_1: & ' static NSString = ns_string ! ( "1" ) ;
989+
990+ let name = NSString :: from_str ( cookie. name ( ) ) ;
991+ let value = NSString :: from_str ( cookie. value ( ) ) ;
992+ let path = cookie. path ( ) . map_or_else ( NSString :: new, NSString :: from_str) ;
993+ let domain = cookie
994+ . domain ( )
995+ . map_or_else ( NSString :: new, NSString :: from_str) ;
996+
997+ let properties: Retained < NSMutableDictionary < NSHTTPCookiePropertyKey , AnyObject > > =
998+ NSMutableDictionary :: from_slices (
999+ & [
1000+ NSHTTPCookieName ,
1001+ NSHTTPCookieValue ,
1002+ NSHTTPCookiePath ,
1003+ NSHTTPCookieDomain ,
1004+ ] ,
1005+ & [ & * name, & * value, & * path, & * domain] ,
1006+ ) ;
1007+
1008+ if let Some ( max_age_) = cookie. max_age ( ) {
1009+ let max_age = NSString :: from_str ( & max_age_. whole_seconds ( ) . to_string ( ) ) ;
1010+ properties. insert ( NSHTTPCookieMaximumAge , & * max_age) ;
1011+ properties. insert ( NSHTTPCookieVersion , nstring_1) ;
1012+ } else if let Some ( dt) = cookie. expires_datetime ( ) {
1013+ let expires = NSDate :: dateWithTimeIntervalSince1970 ( dt. unix_timestamp ( ) as f64 ) ;
1014+ properties. insert ( NSHTTPCookieExpires , & * expires) ;
1015+ properties. insert ( NSHTTPCookieVersion , nstring_0) ;
1016+ }
1017+
1018+ if let Some ( secure) = cookie. secure ( ) {
1019+ let secure = if secure { nstring_true } else { nstring_false } ;
1020+ properties. insert ( NSHTTPCookieSecure , secure) ;
1021+ }
1022+
1023+ if let Some ( http_only) = cookie. http_only ( ) {
1024+ let http_only = if http_only {
1025+ nstring_true
1026+ } else {
1027+ nstring_false
1028+ } ;
1029+ // ref:
1030+ // - <https://stackoverflow.com/a/41697557>
1031+ // - <https://developer.apple.com/forums/thread/701770?answerId=706717022#706717022>
1032+ properties. insert ( ns_string ! ( "HttpOnly" ) , http_only) ;
1033+ }
1034+
1035+ let wkwebview_cookie = NSHTTPCookie :: cookieWithProperties ( & properties)
1036+ . expect ( "failed to create wkwebview cookie, report this as bug to `wry`" ) ;
1037+
1038+ // check if `HttpOnly` works as expected
1039+ debug_assert_eq ! (
1040+ wkwebview_cookie. isHTTPOnly( ) ,
1041+ cookie. http_only( ) . unwrap_or( false ) ,
1042+ "HTTPOnly mismatch, report this as bug to `wry`"
1043+ ) ;
1044+
1045+ wkwebview_cookie
1046+ }
1047+
9821048 pub fn cookies_for_url ( & self , url : & str ) -> Result < Vec < cookie:: Cookie < ' static > > > {
9831049 let url = url:: Url :: parse ( url) ?;
9841050
@@ -1026,6 +1092,42 @@ r#"Object.defineProperty(window, 'ipc', {
10261092 }
10271093 }
10281094
1095+ pub fn set_cookie ( & self , cookie : & cookie:: Cookie < ' _ > ) -> Result < ( ) > {
1096+ let ( tx, rx) = std:: sync:: mpsc:: channel ( ) ;
1097+
1098+ unsafe {
1099+ let wkwebview_cookie = Self :: cookie_into_wkwebview ( cookie) ;
1100+ self
1101+ . data_store
1102+ . httpCookieStore ( )
1103+ . setCookie_completionHandler (
1104+ & wkwebview_cookie,
1105+ Some ( & block2:: RcBlock :: new ( move || {
1106+ let _ = tx. send ( ( ) ) ;
1107+ } ) ) ,
1108+ ) ;
1109+ wait_for_blocking_operation ( rx)
1110+ }
1111+ }
1112+
1113+ pub fn delete_cookie ( & self , cookie : & cookie:: Cookie < ' _ > ) -> Result < ( ) > {
1114+ let ( tx, rx) = std:: sync:: mpsc:: channel ( ) ;
1115+
1116+ unsafe {
1117+ let wkwebview_cookie = Self :: cookie_into_wkwebview ( cookie) ;
1118+ self
1119+ . data_store
1120+ . httpCookieStore ( )
1121+ . deleteCookie_completionHandler (
1122+ & wkwebview_cookie,
1123+ Some ( & block2:: RcBlock :: new ( move || {
1124+ let _ = tx. send ( ( ) ) ;
1125+ } ) ) ,
1126+ ) ;
1127+ wait_for_blocking_operation ( rx)
1128+ }
1129+ }
1130+
10291131 #[ cfg( target_os = "macos" ) ]
10301132 pub ( crate ) fn reparent ( & self , window : * mut NSWindow ) -> crate :: Result < ( ) > {
10311133 unsafe {
0 commit comments