QNetworkReply and QNetworAccessManager don't emit `finished` signal
-
Hello,
I am trying to access an API which requires authentication, but when I set incorrect bearer token in the header both reply and network manager don't emit finished signal.
reply.isFinished()
->False
reply.error()
->NoError
reply.isRunning()
->True
If I remove token, then everything's fine and request fails with an error
ContentAccessDenied: 201
If I set the correct token, then everything's working too
If I use therequests
library with an incorrect token, then everything works: the answer has status code401
The only thing that I came up with is using
setTransferTimeout
and waiting for the request to abort after this timeoutHere is an example of what I'm trying to run:
import sys from PyQt6.QtCore import QUrl from PyQt6.QtNetwork import QNetworkReply from PyQt6.QtNetwork import QNetworkRequest from PyQt6.QtNetwork import QNetworkAccessManager from PyQt6.QtWidgets import QApplication class ApiAccess: def __init__(self) -> None: self.manager = QNetworkAccessManager() self.manager.finished.connect(self.on_manager_finished) self.reply = None self.token = "123" def get(self, url: QUrl) -> None: request = QNetworkRequest(url) request.setRawHeader(b"Authorization", f"Bearer {self.token}".encode("utf-8")) request.setRawHeader(b"User-Agent", b"MyUserAgent") self.reply = self.manager.get(request) self.reply.finished.connect(self.on_reply_finished) self.reply.errorOccurred.connect(self.on_reply_error) def on_manager_finished(self, reply: QNetworkReply) -> None: print(reply) def on_reply_error(self, error: QNetworkReply.NetworkError) -> None: print(error) def on_reply_finished(self) -> None: data = self.reply.readAll().data() print(data) def main(): app = QApplication(sys.argv) api = ApiAccess() url = QUrl("https://api.someresource.com/path?query") api.get(url) return app.exec() if __name__ == "__main__": raise SystemExit(main())
Is this a bug, or am I missing something? (PyQt6 6.6.1)
-
i found out that apparently it has nothing to do with either contents or headers,
and the real reason is: the request was using HTTP/2 protocol
disabling HTTP/2 (request.setAttribute(request.Attribute.Http2AllowedAttribute, False)
) solves my problembut what's wrong with HTTP/2 is yet to be figured out
-
Hi and welcome to devnet,
Did you already check the traffic with Wireshark to see the answer you are getting back from the server ?
-
@Ronel_qtmaster unfortunately, that didn't help
-
For now I'm pretty sure that this is related to QTBUG-122281, because when I connect the
metaDataChanged
signal and look into reply's headers, they contain information about the invalid token, but nothing happens after -
@SGaist hmm, I haven't encountered this issue for other services
At first I thought that the problem is withwww-authenticate
header field
So I found the API which also sends it (https://registry-1.docker.io/v2/_catalog
, for example), and it works fine (my API sends some other attributes inwww-authenticate
header, but they are all valid)The other difference I noticed, my API doesn't send any content (
answer.content == b''
), and all API I've tried so far send a non-empty error message, so maybe my problem lies here -
i don't know, looks like it stuck somewhere in the
QIODevice::read
?(Pdb) self.reply.isOpen() True (Pdb) self.reply.bytesAvailable() 0 (Pdb) self.reply.read(1000) b'' (Pdb) self.reply.read(1000) b'' (Pdb) self.reply.read(1000) b'' (Pdb) self.reply.read(1000) b'' (Pdb) self.reply.read(1000) b'' (Pdb) self.reply.close() got reply error! NetworkError.OperationCanceledError download progress! received=0 total=0 manager finished! QIODevice::read (QNetworkReplyHttpImpl): device not open reply finished! b''
and after i manually close reply it says, that device is not open and emits all the signals i want it to emit
i also made up an http server, which sends similar headers and empty content and it magically works! (but with this "manual close" it has some different output:
self.reply.isOpen()=True got reply error! NetworkError.OperationCanceledError download progress! received=0 total=0 manager finished! QIODevice::read (QNetworkReplyHttpImpl): device not open reply finished! b'' QNetworkReplyImplPrivate::error: Internal problem, this method must only be called once.
i have no ideas. think i probably should give up and create workarounds
-
@xueqli before working around, please open a ticket on the bug report system with your findings. It seems you have a valid case to make.
-
i found out that apparently it has nothing to do with either contents or headers,
and the real reason is: the request was using HTTP/2 protocol
disabling HTTP/2 (request.setAttribute(request.Attribute.Http2AllowedAttribute, False)
) solves my problembut what's wrong with HTTP/2 is yet to be figured out
-
-
Thanks for the link and thorough spelunking !
Since you have a Python reproducer, you should add it to the bug report, it will make things easier for developers to reproduce :-)