Implement ignoring ssl errors in qt backend

This commit is contained in:
Kovid Goyal 2024-08-14 13:27:36 +05:30
parent 7a43916d6c
commit 918eb72335
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
3 changed files with 18 additions and 11 deletions

View File

@ -60,10 +60,11 @@ class FakeResponse:
class Browser: class Browser:
def __init__(self, user_agent: str = '', headers: tuple[tuple[str, str], ...] = (), start_worker: bool = False): def __init__(self, user_agent: str = '', headers: tuple[tuple[str, str], ...] = (), verify_ssl_certificates: bool = True, start_worker: bool = False):
self.tdir = '' self.tdir = ''
self.worker = self.dispatcher = None self.worker = self.dispatcher = None
self.dispatch_map = {} self.dispatch_map = {}
self.verify_ssl_certificates = verify_ssl_certificates
self.id_counter = 0 self.id_counter = 0
self.addheaders: list[tuple[str, str]] = list(headers) self.addheaders: list[tuple[str, str]] = list(headers)
self.user_agent = user_agent self.user_agent = user_agent
@ -145,7 +146,7 @@ class Browser:
with self.lock: with self.lock:
if not self.tdir: if not self.tdir:
self.tdir = PersistentTemporaryDirectory() self.tdir = PersistentTemporaryDirectory()
self.worker = run_worker(self.tdir, self.user_agent) self.worker = run_worker(self.tdir, self.user_agent, self.verify_ssl_certificates)
self.dispatcher = Thread(target=self._dispatch, daemon=True) self.dispatcher = Thread(target=self._dispatch, daemon=True)
self.dispatcher.start() self.dispatcher.start()
@ -189,9 +190,9 @@ class Browser:
self.shutdown() self.shutdown()
def run_worker(tdir: str, user_agent: str): def run_worker(tdir: str, user_agent: str, verify_ssl_certificates: bool):
from calibre.utils.ipc.simple_worker import start_pipe_worker from calibre.utils.ipc.simple_worker import start_pipe_worker
return start_pipe_worker(f'from calibre.scraper.qt import worker; worker({tdir!r}, {user_agent!r})') return start_pipe_worker(f'from calibre.scraper.qt import worker; worker({tdir!r}, {user_agent!r}, {verify_ssl_certificates!r})')
def worker(*args): def worker(*args):

View File

@ -18,6 +18,7 @@ from qt.core import (
QNetworkReply, QNetworkReply,
QNetworkRequest, QNetworkRequest,
QObject, QObject,
QSslError,
Qt, Qt,
QTimer, QTimer,
QUrl, QUrl,
@ -82,10 +83,9 @@ class DownloadRequest(QObject):
self.req_id: int = req_id self.req_id: int = req_id
self.created_at = self.last_activity_at = monotonic() self.created_at = self.last_activity_at = monotonic()
self.timeout = timeout self.timeout = timeout
self.reply.downloadProgress.connect(self.on_download_progress) self.reply.downloadProgress.connect(self.on_download_progress, type=Qt.ConnectionType.QueuedConnection)
self.reply.uploadProgress.connect(self.on_upload_progress) self.reply.uploadProgress.connect(self.on_upload_progress, type=Qt.ConnectionType.QueuedConnection)
# self.reply.readyRead.connect(self.on_data_available) # self.reply.readyRead.connect(self.on_data_available)
self.reply.sslErrors.connect(self.on_ssl_errors)
def on_download_progress(self, bytes_received: int, bytes_total: int) -> None: def on_download_progress(self, bytes_received: int, bytes_total: int) -> None:
self.last_activity_at = monotonic() self.last_activity_at = monotonic()
@ -141,9 +141,10 @@ class FetchBackend(QNetworkAccessManager):
set_user_agent_signal = pyqtSignal(str) set_user_agent_signal = pyqtSignal(str)
download_finished = pyqtSignal(object) download_finished = pyqtSignal(object)
def __init__(self, output_dir: str = '', cache_name: str = '', parent: QObject = None, user_agent: str = '') -> None: def __init__(self, output_dir: str = '', cache_name: str = '', parent: QObject = None, user_agent: str = '', verify_ssl_certificates: bool = True) -> None:
super().__init__(parent) super().__init__(parent)
self.cookie_jar = CookieJar(self) self.cookie_jar = CookieJar(self)
self.verify_ssl_certificates = verify_ssl_certificates
self.setCookieJar(self.cookie_jar) self.setCookieJar(self.cookie_jar)
self.user_agent = user_agent or random_common_chrome_user_agent() self.user_agent = user_agent or random_common_chrome_user_agent()
self.setTransferTimeout(int(default_timeout * 1000)) self.setTransferTimeout(int(default_timeout * 1000))
@ -154,6 +155,7 @@ class FetchBackend(QNetworkAccessManager):
self.set_user_agent_signal.connect(self.set_user_agent, type=Qt.ConnectionType.QueuedConnection) self.set_user_agent_signal.connect(self.set_user_agent, type=Qt.ConnectionType.QueuedConnection)
self.input_finished.connect(self.on_input_finished, type=Qt.ConnectionType.QueuedConnection) self.input_finished.connect(self.on_input_finished, type=Qt.ConnectionType.QueuedConnection)
self.finished.connect(self.on_reply_finished, type=Qt.ConnectionType.QueuedConnection) self.finished.connect(self.on_reply_finished, type=Qt.ConnectionType.QueuedConnection)
self.sslErrors.connect(self.on_ssl_errors)
self.live_requests: set[DownloadRequest] = set() self.live_requests: set[DownloadRequest] = set()
self.all_request_cookies: list[QNetworkCookie] = [] self.all_request_cookies: list[QNetworkCookie] = []
self.timeout_timer = t = QTimer(self) self.timeout_timer = t = QTimer(self)
@ -213,6 +215,10 @@ class FetchBackend(QNetworkAccessManager):
if not self.timeout_timer.isActive(): if not self.timeout_timer.isActive():
self.timeout_timer.start() self.timeout_timer.start()
def on_ssl_errors(self, reply: QNetworkReply, errors: list[QSslError]) -> None:
if not self.verify_ssl_certificates:
reply.ignoreSslErrors()
def on_reply_finished(self, reply: QNetworkReply) -> None: def on_reply_finished(self, reply: QNetworkReply) -> None:
reply.deleteLater() reply.deleteLater()
for x in tuple(self.live_requests): for x in tuple(self.live_requests):
@ -293,10 +299,10 @@ def read_commands(backend: FetchBackend, tdir: str) -> None:
backend.input_finished.emit(error_msg) backend.input_finished.emit(error_msg)
def worker(tdir: str, user_agent: str) -> None: def worker(tdir: str, user_agent: str, verify_ssl_certificates: bool) -> None:
app = QApplication.instance() app = QApplication.instance()
sys.stdout = sys.stderr sys.stdout = sys.stderr
backend = FetchBackend(parent=app, user_agent=user_agent, output_dir=tdir) backend = FetchBackend(parent=app, user_agent=user_agent, output_dir=tdir, verify_ssl_certificates=verify_ssl_certificates)
try: try:
read_thread = Thread(target=read_commands, args=(backend, tdir), daemon=True) read_thread = Thread(target=read_commands, args=(backend, tdir), daemon=True)
read_thread.start() read_thread.start()

View File

@ -573,7 +573,7 @@ class BasicNewsRecipe(Recipe):
self.log('Using user agent:', kwargs['user_agent']) self.log('Using user agent:', kwargs['user_agent'])
if self.browser_type == 'qt': if self.browser_type == 'qt':
from calibre.scraper.qt import Browser from calibre.scraper.qt import Browser
return Browser(user_agent=kwargs['user_agent']) return Browser(user_agent=kwargs['user_agent'], verify_ssl_certificates=kwargs.get('verify_ssl_certificates', False))
br = browser(*args, **kwargs) br = browser(*args, **kwargs)
br.addheaders += [('Accept', '*/*')] br.addheaders += [('Accept', '*/*')]
if self.handle_gzip: if self.handle_gzip: