network_session.go RawHistoryFolder
1package webkit
2
3import (
4 "fmt"
5 "log"
6
7 webkit "github.com/diamondburned/gotk4-webkitgtk/pkg/webkit/v6"
8)
9
10var (
11 // globalNetworkSession holds the persistent network session to prevent garbage collection
12 // This must be kept alive for the entire application lifetime
13 globalNetworkSession *webkit.NetworkSession
14)
15
16// InitPersistentSession creates and initializes a persistent NetworkSession
17// with the provided data and cache directories.
18// This should be called before creating any WebViews to ensure they use persistent storage.
19// Returns an error if initialization fails.
20//
21// IMPORTANT: Once created, this session is stored globally and will be used by all
22// WebViews created afterward, as per WebKitGTK 6.0's design where the first created
23// session becomes the default for the network process.
24func InitPersistentSession(dataDir, cacheDir string) error {
25 // If session already exists, return success (idempotent)
26 // This ensures we only create ONE session for the entire application
27 if globalNetworkSession != nil {
28 log.Printf("[webkit] Using existing persistent network session")
29 return nil
30 }
31
32 // Create persistent network session using gotk4 API
33 // Per WebKitGTK 6.0 docs: "The first WebKitNetworkSession created becomes the default"
34 session := webkit.NewNetworkSession(dataDir, cacheDir)
35 if session == nil {
36 return fmt.Errorf("failed to create persistent network session")
37 }
38
39 // Store the session globally to prevent garbage collection
40 // This is CRITICAL - if the session is GC'd, WebKit falls back to ephemeral storage
41 globalNetworkSession = session
42
43 log.Printf("[webkit] Persistent network session created: data=%s, cache=%s", dataDir, cacheDir)
44
45 // Verify the session is not ephemeral
46 if session.IsEphemeral() {
47 return fmt.Errorf("created session is ephemeral despite providing data directories")
48 }
49
50 // Verify the WebsiteDataManager is not ephemeral
51 websiteDataManager := session.WebsiteDataManager()
52 if websiteDataManager == nil {
53 return fmt.Errorf("failed to get website data manager from network session")
54 }
55 if websiteDataManager.IsEphemeral() {
56 return fmt.Errorf("website data manager is ephemeral despite providing data directories")
57 }
58 log.Printf("[webkit] WebsiteDataManager verified as non-ephemeral")
59
60 // Configure CookieManager for persistent cookie storage
61 // This is REQUIRED - without this, cookies are not persisted to disk
62 cookieManager := session.CookieManager()
63 if cookieManager == nil {
64 return fmt.Errorf("failed to get cookie manager from network session")
65 }
66
67 // Set cookie persistent storage to SQLite database
68 // Format: filepath.Join(dataDir, "cookies.db")
69 cookiePath := dataDir + "/cookies.db"
70 cookieManager.SetPersistentStorage(cookiePath, webkit.CookiePersistentStorageSqlite)
71
72 // Set cookie accept policy to no third-party (default)
73 cookieManager.SetAcceptPolicy(webkit.CookiePolicyAcceptNoThirdParty)
74
75 log.Printf("[webkit] Cookie manager configured: storage=%s, policy=no-third-party", cookiePath)
76
77 // Enable persistent credential storage (HTTP auth, etc.)
78 session.SetPersistentCredentialStorageEnabled(true)
79
80 // Configure TLS errors to emit signals instead of failing silently
81 // This enables the load-failed-with-tls-errors signal
82 session.SetTLSErrorsPolicy(webkit.TLSErrorsPolicyFail)
83 log.Printf("[webkit] TLS errors policy set to FAIL (signals enabled)")
84
85 // Verify this is indeed the default session now
86 defaultSession := webkit.NetworkSessionGetDefault()
87 if defaultSession == nil {
88 return fmt.Errorf("default network session is nil after creating persistent session")
89 }
90
91 // Check if they're the same session by comparing ephemeral status
92 if defaultSession.IsEphemeral() {
93 return fmt.Errorf("default network session is ephemeral after creating persistent session")
94 }
95
96 log.Printf("[webkit] Network session verified as persistent and set as default")
97 return nil
98}
99
100// GetGlobalNetworkSession returns the global network session.
101// Returns nil if InitPersistentSession hasn't been called successfully.
102func GetGlobalNetworkSession() *webkit.NetworkSession {
103 return globalNetworkSession
104}
105
106// PrefetchDNS prefetches DNS for the given hostname to speed up future requests.
107// This is useful for preloading DNS for links that the user might click.
108// Safe to call even if the hostname is invalid or session is not initialized.
109func PrefetchDNS(hostname string) {
110 if globalNetworkSession == nil {
111 return // Session not initialized yet
112 }
113 if hostname == "" {
114 return // Nothing to prefetch
115 }
116 globalNetworkSession.PrefetchDns(hostname)
117}