src/network/access/qhttpnetworkreply.cpp
branchRCL_3
changeset 7 3f74d0d4af4c
parent 4 3b1da2848fc7
equal deleted inserted replaced
6:dee5afe5301f 7:3f74d0d4af4c
   217 
   217 
   218 QHttpNetworkReplyPrivate::~QHttpNetworkReplyPrivate()
   218 QHttpNetworkReplyPrivate::~QHttpNetworkReplyPrivate()
   219 {
   219 {
   220 }
   220 }
   221 
   221 
   222 void QHttpNetworkReplyPrivate::clear()
   222 void QHttpNetworkReplyPrivate::clearHttpLayerInformation()
   223 {
   223 {
   224     state = NothingDoneState;
   224     state = NothingDoneState;
   225     statusCode = 100;
   225     statusCode = 100;
   226     bodyLength = 0;
   226     bodyLength = 0;
   227     contentRead = 0;
   227     contentRead = 0;
   228     totalProgress = 0;
   228     totalProgress = 0;
   229     currentChunkSize = 0;
   229     currentChunkSize = 0;
   230     currentChunkRead = 0;
   230     currentChunkRead = 0;
   231     connectionCloseEnabled = true;
   231     connectionCloseEnabled = true;
   232     connection = 0;
       
   233 #ifndef QT_NO_COMPRESS
   232 #ifndef QT_NO_COMPRESS
   234     if (initInflate)
   233     if (initInflate)
   235         inflateEnd(&inflateStrm);
   234         inflateEnd(&inflateStrm);
   236 #endif
   235 #endif
   237     initInflate = false;
   236     initInflate = false;
   238     streamEnd = false;
   237     streamEnd = false;
       
   238     fields.clear();
       
   239 }
       
   240 
       
   241 // TODO: Isn't everything HTTP layer related? We don't need to set connection and connectionChannel to 0 at all
       
   242 void QHttpNetworkReplyPrivate::clear()
       
   243 {
       
   244     connection = 0;
       
   245     connectionChannel = 0;
   239     autoDecompress = false;
   246     autoDecompress = false;
   240     fields.clear();
   247     clearHttpLayerInformation();
   241 }
   248 }
   242 
   249 
   243 // QHttpNetworkReplyPrivate
   250 // QHttpNetworkReplyPrivate
   244 qint64 QHttpNetworkReplyPrivate::bytesAvailable() const
   251 qint64 QHttpNetworkReplyPrivate::bytesAvailable() const
   245 {
   252 {
   421 }
   428 }
   422 #endif
   429 #endif
   423 
   430 
   424 qint64 QHttpNetworkReplyPrivate::readStatus(QAbstractSocket *socket)
   431 qint64 QHttpNetworkReplyPrivate::readStatus(QAbstractSocket *socket)
   425 {
   432 {
       
   433     if (fragment.isEmpty()) {
       
   434         // reserve bytes for the status line. This is better than always append() which reallocs the byte array
       
   435         fragment.reserve(32);
       
   436     }
       
   437 
   426     qint64 bytes = 0;
   438     qint64 bytes = 0;
   427     char c;
   439     char c;
   428 
   440     qint64 haveRead = 0;
   429     while (socket->bytesAvailable()) {
   441 
       
   442     do {
       
   443         haveRead = socket->read(&c, 1);
       
   444         if (haveRead == -1)
       
   445             return -1; // unexpected EOF
       
   446         else if (haveRead == 0)
       
   447             break; // read more later
       
   448 
       
   449         bytes++;
       
   450 
   430         // allow both CRLF & LF (only) line endings
   451         // allow both CRLF & LF (only) line endings
   431         if (socket->peek(&c, 1) == 1 && c == '\n') {
   452         if (c == '\n') {
   432             bytes += socket->read(&c, 1); // read the "n"
       
   433             // remove the CR at the end
   453             // remove the CR at the end
   434             if (fragment.endsWith('\r')) {
   454             if (fragment.endsWith('\r')) {
   435                 fragment.truncate(fragment.length()-1);
   455                 fragment.truncate(fragment.length()-1);
   436             }
   456             }
   437             bool ok = parseStatus(fragment);
   457             bool ok = parseStatus(fragment);
   440             if (!ok) {
   460             if (!ok) {
   441                 return -1;
   461                 return -1;
   442             }
   462             }
   443             break;
   463             break;
   444         } else {
   464         } else {
   445             c = 0;
       
   446             int haveRead = socket->read(&c, 1);
       
   447             if (haveRead == -1)
       
   448                 return -1;
       
   449             bytes += haveRead;
       
   450             fragment.append(c);
   465             fragment.append(c);
   451         }
   466         }
   452 
   467 
   453         // is this a valid reply?
   468         // is this a valid reply?
   454         if (fragment.length() >= 5 && !fragment.startsWith("HTTP/"))
   469         if (fragment.length() >= 5 && !fragment.startsWith("HTTP/"))
   455         {
   470         {
   456             fragment.clear();
   471             fragment.clear();
   457             return -1;
   472             return -1;
   458         }
   473         }
   459 
   474     } while (haveRead == 1);
   460     }
       
   461 
   475 
   462     return bytes;
   476     return bytes;
   463 }
   477 }
   464 
   478 
   465 bool QHttpNetworkReplyPrivate::parseStatus(const QByteArray &status)
   479 bool QHttpNetworkReplyPrivate::parseStatus(const QByteArray &status)
   498     return ok && uint(majorVersion) <= 9 && uint(minorVersion) <= 9;
   512     return ok && uint(majorVersion) <= 9 && uint(minorVersion) <= 9;
   499 }
   513 }
   500 
   514 
   501 qint64 QHttpNetworkReplyPrivate::readHeader(QAbstractSocket *socket)
   515 qint64 QHttpNetworkReplyPrivate::readHeader(QAbstractSocket *socket)
   502 {
   516 {
       
   517     if (fragment.isEmpty()) {
       
   518         // according to http://dev.opera.com/articles/view/mama-http-headers/ the average size of the header
       
   519         // block is 381 bytes.
       
   520         // reserve bytes. This is better than always append() which reallocs the byte array.
       
   521         fragment.reserve(512);
       
   522     }
       
   523 
   503     qint64 bytes = 0;
   524     qint64 bytes = 0;
   504     char c = 0;
   525     char c = 0;
   505     bool allHeaders = false;
   526     bool allHeaders = false;
   506     while (!allHeaders && socket->bytesAvailable()) {
   527     qint64 haveRead = 0;
   507         if (socket->peek(&c, 1) == 1 && c == '\n') {
   528     do {
   508             // check for possible header endings. As per HTTP rfc,
   529         haveRead = socket->read(&c, 1);
   509             // the header endings will be marked by CRLFCRLF. But
   530         if (haveRead == 0) {
   510             // we will allow CRLFLF, LFLF & CRLFCRLF
   531             // read more later
   511             if (fragment.endsWith("\n\r") || fragment.endsWith('\n'))
   532             break;
   512                 allHeaders = true;
   533         } else if (haveRead == -1) {
   513         }
   534             // connection broke down
   514         bytes += socket->read(&c, 1);
   535             return -1;
   515         fragment.append(c);
   536         } else {
   516     }
   537             fragment.append(c);
       
   538             bytes++;
       
   539 
       
   540             if (c == '\n') {
       
   541                 // check for possible header endings. As per HTTP rfc,
       
   542                 // the header endings will be marked by CRLFCRLF. But
       
   543                 // we will allow CRLFCRLF, CRLFLF, LFLF
       
   544                 if (fragment.endsWith("\r\n\r\n")
       
   545                     || fragment.endsWith("\r\n\n")
       
   546                     || fragment.endsWith("\n\n"))
       
   547                     allHeaders = true;
       
   548 
       
   549                 // there is another case: We have no headers. Then the fragment equals just the line ending
       
   550                 if ((fragment.length() == 2 && fragment.endsWith("\r\n"))
       
   551                     || (fragment.length() == 1 && fragment.endsWith("\n")))
       
   552                     allHeaders = true;
       
   553             }
       
   554         }
       
   555     } while (!allHeaders && haveRead > 0);
       
   556 
   517     // we received all headers now parse them
   557     // we received all headers now parse them
   518     if (allHeaders) {
   558     if (allHeaders) {
   519         parseHeader(fragment);
   559         parseHeader(fragment);
   520         state = ReadingDataState;
   560         state = ReadingDataState;
   521         fragment.clear(); // next fragment
   561         fragment.clear(); // next fragment
   773 #ifndef QT_NO_OPENSSL
   813 #ifndef QT_NO_OPENSSL
   774 
   814 
   775 QSslConfiguration QHttpNetworkReply::sslConfiguration() const
   815 QSslConfiguration QHttpNetworkReply::sslConfiguration() const
   776 {
   816 {
   777     Q_D(const QHttpNetworkReply);
   817     Q_D(const QHttpNetworkReply);
   778     if (d->connection)
   818 
   779         return d->connection->d_func()->sslConfiguration(*this);
   819     if (!d->connectionChannel)
   780     return QSslConfiguration();
   820         return QSslConfiguration();
       
   821 
       
   822     QSslSocket *sslSocket = qobject_cast<QSslSocket*>(d->connectionChannel->socket);
       
   823     if (!sslSocket)
       
   824         return QSslConfiguration();
       
   825 
       
   826     return sslSocket->sslConfiguration();
   781 }
   827 }
   782 
   828 
   783 void QHttpNetworkReply::setSslConfiguration(const QSslConfiguration &config)
   829 void QHttpNetworkReply::setSslConfiguration(const QSslConfiguration &config)
   784 {
   830 {
   785     Q_D(QHttpNetworkReply);
   831     Q_D(QHttpNetworkReply);