Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Qt for Python
  4. QNetworkReply and QNetworAccessManager don't emit `finished` signal
Qt 6.11 is out! See what's new in the release blog

QNetworkReply and QNetworAccessManager don't emit `finished` signal

Scheduled Pinned Locked Moved Solved Qt for Python
14 Posts 3 Posters 2.6k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • X Offline
    X Offline
    xueqli
    wrote on last edited by xueqli
    #1

    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 the requests library with an incorrect token, then everything works: the answer has status code 401

    The only thing that I came up with is using setTransferTimeout and waiting for the request to abort after this timeout

    Here 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)

    Ronel_qtmasterR 1 Reply Last reply
    0
    • X Offline
      X Offline
      xueqli
      wrote on last edited by xueqli
      #11

      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 problem

      but what's wrong with HTTP/2 is yet to be figured out

      SGaistS 1 Reply Last reply
      1
      • SGaistS Offline
        SGaistS Offline
        SGaist
        Lifetime Qt Champion
        wrote on last edited by
        #2

        Hi and welcome to devnet,

        Did you already check the traffic with Wireshark to see the answer you are getting back from the server ?

        Interested in AI ? www.idiap.ch
        Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

        X 1 Reply Last reply
        1
        • X xueqli

          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 the requests library with an incorrect token, then everything works: the answer has status code 401

          The only thing that I came up with is using setTransferTimeout and waiting for the request to abort after this timeout

          Here 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)

          Ronel_qtmasterR Offline
          Ronel_qtmasterR Offline
          Ronel_qtmaster
          wrote on last edited by
          #3

          @xueqli in the url, change https to http and try again

          X 1 Reply Last reply
          0
          • SGaistS SGaist

            Hi and welcome to devnet,

            Did you already check the traffic with Wireshark to see the answer you are getting back from the server ?

            X Offline
            X Offline
            xueqli
            wrote on last edited by
            #4

            @SGaist Hi! What exactly am I supposed to look at in the traffic?
            It looks like the server does respond to the requests
            Here are some screens:
            qt_correct_token.png qt_wrong_token.png requests_correct_token.png requests_wrong_token.png

            1 Reply Last reply
            0
            • Ronel_qtmasterR Ronel_qtmaster

              @xueqli in the url, change https to http and try again

              X Offline
              X Offline
              xueqli
              wrote on last edited by
              #5

              @Ronel_qtmaster unfortunately, that didn't help

              1 Reply Last reply
              0
              • X Offline
                X Offline
                xueqli
                wrote on last edited by
                #6

                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

                SGaistS 1 Reply Last reply
                0
                • X xueqli

                  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

                  SGaistS Offline
                  SGaistS Offline
                  SGaist
                  Lifetime Qt Champion
                  wrote on last edited by
                  #7

                  @xueqli just to rule out the obvious, you have the same issue if you send requests to a different service ?

                  Is there one that is accessible that you can share for testing purposes so we can test it ?

                  Interested in AI ? www.idiap.ch
                  Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                  X 1 Reply Last reply
                  1
                  • SGaistS SGaist

                    @xueqli just to rule out the obvious, you have the same issue if you send requests to a different service ?

                    Is there one that is accessible that you can share for testing purposes so we can test it ?

                    X Offline
                    X Offline
                    xueqli
                    wrote on last edited by
                    #8

                    @SGaist hmm, I haven't encountered this issue for other services
                    At first I thought that the problem is with www-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 in www-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

                    1 Reply Last reply
                    0
                    • X Offline
                      X Offline
                      xueqli
                      wrote on last edited by
                      #9

                      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

                      SGaistS 1 Reply Last reply
                      0
                      • X xueqli

                        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

                        SGaistS Offline
                        SGaistS Offline
                        SGaist
                        Lifetime Qt Champion
                        wrote on last edited by
                        #10

                        @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.

                        Interested in AI ? www.idiap.ch
                        Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                        1 Reply Last reply
                        1
                        • X Offline
                          X Offline
                          xueqli
                          wrote on last edited by xueqli
                          #11

                          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 problem

                          but what's wrong with HTTP/2 is yet to be figured out

                          SGaistS 1 Reply Last reply
                          1
                          • X xueqli has marked this topic as solved on
                          • X xueqli

                            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 problem

                            but what's wrong with HTTP/2 is yet to be figured out

                            SGaistS Offline
                            SGaistS Offline
                            SGaist
                            Lifetime Qt Champion
                            wrote on last edited by
                            #12

                            @xueqli Nice catch !

                            I would still recommend opening a ticket.

                            Interested in AI ? www.idiap.ch
                            Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                            X 1 Reply Last reply
                            1
                            • SGaistS SGaist

                              @xueqli Nice catch !

                              I would still recommend opening a ticket.

                              X Offline
                              X Offline
                              xueqli
                              wrote on last edited by
                              #13

                              @SGaist yea, i did: https://bugreports.qt.io/browse/QTBUG-123891
                              (and turned out both HTTP/2 and www-authenticate headers are required to reproduce this)

                              1 Reply Last reply
                              1
                              • SGaistS Offline
                                SGaistS Offline
                                SGaist
                                Lifetime Qt Champion
                                wrote on last edited by
                                #14

                                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 :-)

                                Interested in AI ? www.idiap.ch
                                Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                                1 Reply Last reply
                                1

                                • Login

                                • Login or register to search.
                                • First post
                                  Last post
                                0
                                • Categories
                                • Recent
                                • Tags
                                • Popular
                                • Users
                                • Groups
                                • Search
                                • Get Qt Extensions
                                • Unsolved