Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/client_handler/cookie_access_filter.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// All rights reserved. Licensed under BSD 3-clause license.
// Project website: https://github.com/cztomczak/cefpython

#pragma once
#include "common/cefpython_public_api.h"
#include "include/cef_resource_request_handler.h"

Expand Down
14 changes: 14 additions & 0 deletions src/client_handler/request_handler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,20 @@
#include "include/base/cef_callback.h"


CefRefPtr<CefResourceRequestHandler> RequestHandler::GetResourceRequestHandler(
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefRequest> request,
bool is_navigation,
bool is_download,
const CefString& request_initiator,
bool& disable_default_handling) {
// Returning a handler enables the CookieAccessFilter, which delivers the
// CanSendCookie/CanSaveCookie callbacks (issue #676).
return new ResourceRequestHandler();
}


bool RequestHandler::OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefRequest> request,
Expand Down
10 changes: 10 additions & 0 deletions src/client_handler/request_handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "include/cef_request_handler.h"
#include "include/base/cef_callback.h"
#include "cookie_access_filter.h"
#include "resource_request_handler.h"

typedef cef_return_value_t ReturnValue;

Expand All @@ -17,6 +18,15 @@ class RequestHandler : public CefRequestHandler,
RequestHandler(){}
virtual ~RequestHandler(){}

CefRefPtr<CefResourceRequestHandler> GetResourceRequestHandler(
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefRequest> request,
bool is_navigation,
bool is_download,
const CefString& request_initiator,
bool& disable_default_handling) override;

bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefRequest> request,
Expand Down
30 changes: 30 additions & 0 deletions src/client_handler/resource_request_handler.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright (c) 2026 CEF Python, see the Authors file.
// All rights reserved. Licensed under BSD 3-clause license.
// Project website: https://github.com/cztomczak/cefpython

#pragma once
#include "include/cef_resource_request_handler.h"
#include "cookie_access_filter.h"

// Minimal CefResourceRequestHandler that returns a CookieAccessFilter.
// CanSendCookie/CanSaveCookie were moved out of CefRequestHandler into
// CefCookieAccessFilter with the NetworkService migration (CEF based on
// Chromium 75, see CEF issue #2622), reachable only via this intermediate
// interface (CefRequestHandler::GetResourceRequestHandler ->
// CefResourceRequestHandler::GetCookieAccessFilter). Without it the
// CanSendCookie/CanSaveCookie callbacks are never invoked (issue #676).
class ResourceRequestHandler : public CefResourceRequestHandler {
public:
ResourceRequestHandler() {}
virtual ~ResourceRequestHandler() {}

CefRefPtr<CefCookieAccessFilter> GetCookieAccessFilter(
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefRequest> request) override {
return new CookieAccessFilter();
}

private:
IMPLEMENT_REFCOUNTING(ResourceRequestHandler);
};
14 changes: 12 additions & 2 deletions src/frame.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,18 @@ cdef PyFrame GetPyFrame(CefRefPtr[CefFrame] cefFrame):

cdef PyFrame pyFrame
cdef CefString frameId = cefFrame.get().GetIdentifier()
cdef int browserId = cefFrame.get().GetBrowser().get().GetIdentifier()
assert (not frameId.empty() and browserId), "frameId or browserId empty"
cdef CefRefPtr[CefBrowser] cefBrowser = cefFrame.get().GetBrowser()
if not cefBrowser.get():
# Issue #676: CefFrame::GetBrowser() may return NULL when called off
# the UI thread -- e.g. from the IO-thread CanSendCookie/CanSaveCookie
# callbacks for cross-origin subresource requests, or for requests not
# associated with a live frame (service workers / CefURLRequest).
# Raising here prevents a SIGSEGV from the naked .get().GetIdentifier()
# chain that was previously here. Callers that can hit this (the cookie
# filter) guard for it and fall back before calling GetPyFrame.
raise Exception("GetPyFrame(): CefBrowser is NULL"
" (CefFrame.GetBrowser() unavailable off the UI thread?)")
cdef int browserId = cefBrowser.get().GetIdentifier()
cdef str uniqueFrameId = GetUniqueFrameId(browserId, CefToPyString(frameId))

if frameId.empty():
Expand Down
19 changes: 19 additions & 0 deletions src/handlers/cookie_access_filter.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,17 @@ cdef public cpp_bool CookieAccessFilter_CanSendCookie(
# browser was closed.
if IsBrowserClosed(cef_browser):
return False
# Issue #676: This callback runs on the IO thread, where
# CefFrame::GetBrowser() may return NULL (observed for cross-origin
# subresource requests). CEF also documents browser/frame as optional
# ("may be NULL for requests originating from service workers or
# CefURLRequest", cef_resource_request_handler.h > CefCookieAccessFilter).
# Without a resolvable browser we cannot build a PyFrame to dispatch on,
# so log and allow the cookie by default (CEF's own default is true).
if not cef_frame.get() or not cef_frame.get().GetBrowser().get():
Debug("CanSendCookie: no resolvable browser for the request"
" (IO-thread / service-worker request); allowing by default")
return True

browser = GetPyBrowser(cef_browser, "CanSendCookie")
frame = GetPyFrame(cef_frame)
Expand Down Expand Up @@ -64,6 +75,14 @@ cdef public cpp_bool CookieAccessFilter_CanSaveCookie(
# browser was closed.
if IsBrowserClosed(cef_browser):
return False
# Issue #676: see CanSendCookie above. On the IO thread
# CefFrame::GetBrowser() may be NULL (and CEF documents browser/frame
# as optional). Without a resolvable browser we cannot build a PyFrame,
# so log and allow the cookie by default.
if not cef_frame.get() or not cef_frame.get().GetBrowser().get():
Debug("CanSaveCookie: no resolvable browser for the request"
" (IO-thread / service-worker request); allowing by default")
return True

browser = GetPyBrowser(cef_browser, "CanSaveCookie")
frame = GetPyFrame(cef_frame)
Expand Down