Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-134694

QNetworkAccessManager re-sends destructive requests (POST, possibly others) without user intervention

    XMLWordPrintable

Details

    • Bug
    • Resolution: Fixed
    • P0: Blocker
    • 6.5.9, 6.8.4, 6.9.1, 6.10.0 FF
    • 6.9.0
    • Network
    • None
    • 4c9a4ecd3 (dev), 10e546f01 (6.9), f2a599c15 (6.8), c449ff9cb (tqtc/lts-6.5)

    Description

      When using QNAM to send a POST request, if there's an unexpected EOF or an error in the server's reply, QNAM sends the request again.

      For instance:

          QNetworkAccessManager qnam;
          QNetworkRequest req(QUrl("http://localhost:12345/service"));
          auto reply = qnam.post(req, "hello\n");
      

      Run a local faux server with something like nc -l 12345 -k. When the request arrives, type something into nc and press return – QNAM will re-send the POST.

      A quick analysis of the problem:

      QHttpProtocolHandler::_q_receiveReply will call m_channel->handleUnexpectedEOF(); in a number of cases. The common case seems to be if the server side times out and closes the connection after having sent a partial reply.¹

      QHttpNetworkConnectionChannel::handleUnexpectedEOF will then try again, for a maximum of 4 times, before giving up. It will however not check if it is allowed to re-send the request (i.e. the request is idempotent). This will cause a POST to be sent again, causing data losses.

      ¹ But also in case of garbage, like the demo above shows. For instance if you just type nonsense, QHttpHeaderParser::parseStatus returns false. That causes QHttpNetworkReplyPrivate::readStatus to return -1:

                  bool ok = parseStatus(fragment);
                  state = ReadingHeaderState;
                  fragment.clear();
                  if (!ok) {
                      return -1;
                  }
      

      but -1 is for EOF, not for parsing errors! This will also end up in QHttpNetworkConnectionChannel::handleUnexpectedEOF, and eventually cause it to emit the wrong error (RemoteHostClosedError, instead of a protocol-level error – "server sent garbage").

      Attachments

        For Gerrit Dashboard: QTBUG-134694
        # Subject Branch Project Status CR V

        Activity

          People

            manordheim Mårten Nordheim
            peppe Giuseppe D'Angelo
            Votes:
            0 Vote for this issue
            Watchers:
            8 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:

              Gerrit Reviews

                There are no open Gerrit changes