src/qt3support/network/q3http.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the Qt3Support module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include <qplatformdefs.h>
       
    43 #include "q3http.h"
       
    44 
       
    45 #ifndef QT_NO_HTTP
       
    46 
       
    47 #include "q3socket.h"
       
    48 #include "qtextstream.h"
       
    49 #include "qmap.h"
       
    50 #include "qstring.h"
       
    51 #include "qstringlist.h"
       
    52 #include "q3cstring.h"
       
    53 #include "qbuffer.h"
       
    54 #include "q3urloperator.h"
       
    55 #include "qtimer.h"
       
    56 #include "private/q3membuf_p.h"
       
    57 #include "qevent.h"
       
    58 #include "q3url.h"
       
    59 #include "qhttp.h"
       
    60 
       
    61 QT_BEGIN_NAMESPACE
       
    62 
       
    63 //#define Q3HTTP_DEBUG
       
    64 
       
    65 class Q3HttpPrivate
       
    66 {
       
    67 public:
       
    68     Q3HttpPrivate() :
       
    69 	state( Q3Http::Unconnected ),
       
    70 	error( Q3Http::NoError ),
       
    71 	hostname( QString() ),
       
    72 	port( 0 ),
       
    73 	toDevice( 0 ),
       
    74 	postDevice( 0 ),
       
    75 	bytesDone( 0 ),
       
    76 	chunkedSize( -1 ),
       
    77 	idleTimer( 0 )
       
    78     {
       
    79 	pending.setAutoDelete( true );
       
    80     }
       
    81 
       
    82     Q3Socket socket;
       
    83     Q3PtrList<Q3HttpRequest> pending;
       
    84 
       
    85     Q3Http::State state;
       
    86     Q3Http::Error error;
       
    87     QString errorString;
       
    88 
       
    89     QString hostname;
       
    90     Q_UINT16 port;
       
    91 
       
    92     QByteArray buffer;
       
    93     QIODevice* toDevice;
       
    94     QIODevice* postDevice;
       
    95 
       
    96     uint bytesDone;
       
    97     uint bytesTotal;
       
    98     Q_LONG chunkedSize;
       
    99 
       
   100     Q3HttpRequestHeader header;
       
   101 
       
   102     bool readHeader;
       
   103     QString headerStr;
       
   104     Q3HttpResponseHeader response;
       
   105 
       
   106     int idleTimer;
       
   107 
       
   108     Q3Membuf rba;
       
   109 };
       
   110 
       
   111 class Q3HttpRequest
       
   112 {
       
   113 public:
       
   114     Q3HttpRequest()
       
   115     {
       
   116 	id = ++idCounter;
       
   117     }
       
   118     virtual ~Q3HttpRequest()
       
   119     { }
       
   120 
       
   121     virtual void start( Q3Http * ) = 0;
       
   122     virtual bool hasRequestHeader();
       
   123     virtual Q3HttpRequestHeader requestHeader();
       
   124 
       
   125     virtual QIODevice* sourceDevice() = 0;
       
   126     virtual QIODevice* destinationDevice() = 0;
       
   127 
       
   128     int id;
       
   129 
       
   130 private:
       
   131     static int idCounter;
       
   132 };
       
   133 
       
   134 int Q3HttpRequest::idCounter = 0;
       
   135 
       
   136 bool Q3HttpRequest::hasRequestHeader()
       
   137 {
       
   138     return false;
       
   139 }
       
   140 
       
   141 Q3HttpRequestHeader Q3HttpRequest::requestHeader()
       
   142 {
       
   143     return Q3HttpRequestHeader();
       
   144 }
       
   145 
       
   146 /****************************************************
       
   147  *
       
   148  * Q3HttpNormalRequest
       
   149  *
       
   150  ****************************************************/
       
   151 
       
   152 class Q3HttpNormalRequest : public Q3HttpRequest
       
   153 {
       
   154 public:
       
   155     Q3HttpNormalRequest( const Q3HttpRequestHeader &h, QIODevice *d, QIODevice *t ) :
       
   156 	header(h), to(t)
       
   157     {
       
   158 	is_ba = false;
       
   159 	data.dev = d;
       
   160     }
       
   161 
       
   162     Q3HttpNormalRequest( const Q3HttpRequestHeader &h, QByteArray *d, QIODevice *t ) :
       
   163 	header(h), to(t)
       
   164     {
       
   165 	is_ba = true;
       
   166 	data.ba = d;
       
   167     }
       
   168 
       
   169     ~Q3HttpNormalRequest()
       
   170     {
       
   171 	if ( is_ba )
       
   172 	    delete data.ba;
       
   173     }
       
   174 
       
   175     void start( Q3Http * );
       
   176     bool hasRequestHeader();
       
   177     Q3HttpRequestHeader requestHeader();
       
   178 
       
   179     QIODevice* sourceDevice();
       
   180     QIODevice* destinationDevice();
       
   181 
       
   182 protected:
       
   183     Q3HttpRequestHeader header;
       
   184 
       
   185 private:
       
   186     union {
       
   187 	QByteArray *ba;
       
   188 	QIODevice *dev;
       
   189     } data;
       
   190     bool is_ba;
       
   191     QIODevice *to;
       
   192 };
       
   193 
       
   194 void Q3HttpNormalRequest::start( Q3Http *http )
       
   195 {
       
   196     http->d->header = header;
       
   197 
       
   198     if ( is_ba ) {
       
   199 	http->d->buffer = *data.ba;
       
   200 	if ( http->d->buffer.size() > 0 )
       
   201 	    http->d->header.setContentLength( http->d->buffer.size() );
       
   202 
       
   203 	http->d->postDevice = 0;
       
   204     } else {
       
   205 	http->d->buffer = QByteArray();
       
   206 
       
   207 	if ( data.dev && ( data.dev->isOpen() || data.dev->open(IO_ReadOnly) ) ) {
       
   208 	    http->d->postDevice = data.dev;
       
   209 	    if ( http->d->postDevice->size() > 0 )
       
   210 		http->d->header.setContentLength( http->d->postDevice->size() );
       
   211 	} else {
       
   212 	    http->d->postDevice = 0;
       
   213 	}
       
   214     }
       
   215 
       
   216     if ( to && ( to->isOpen() || to->open(IO_WriteOnly) ) )
       
   217 	http->d->toDevice = to;
       
   218     else
       
   219 	http->d->toDevice = 0;
       
   220 
       
   221     http->sendRequest();
       
   222 }
       
   223 
       
   224 bool Q3HttpNormalRequest::hasRequestHeader()
       
   225 {
       
   226     return true;
       
   227 }
       
   228 
       
   229 Q3HttpRequestHeader Q3HttpNormalRequest::requestHeader()
       
   230 {
       
   231     return header;
       
   232 }
       
   233 
       
   234 QIODevice* Q3HttpNormalRequest::sourceDevice()
       
   235 {
       
   236     if ( is_ba )
       
   237 	return 0;
       
   238     return data.dev;
       
   239 }
       
   240 
       
   241 QIODevice* Q3HttpNormalRequest::destinationDevice()
       
   242 {
       
   243     return to;
       
   244 }
       
   245 
       
   246 /****************************************************
       
   247  *
       
   248  * Q3HttpPGHRequest
       
   249  * (like a Q3HttpNormalRequest, but for the convenience
       
   250  * functions put(), get() and head() -- i.e. set the
       
   251  * host header field correctly before sending the
       
   252  * request)
       
   253  *
       
   254  ****************************************************/
       
   255 
       
   256 class Q3HttpPGHRequest : public Q3HttpNormalRequest
       
   257 {
       
   258 public:
       
   259     Q3HttpPGHRequest( const Q3HttpRequestHeader &h, QIODevice *d, QIODevice *t ) :
       
   260 	Q3HttpNormalRequest( h, d, t )
       
   261     { }
       
   262 
       
   263     Q3HttpPGHRequest( const Q3HttpRequestHeader &h, QByteArray *d, QIODevice *t ) :
       
   264 	Q3HttpNormalRequest( h, d, t )
       
   265     { }
       
   266 
       
   267     ~Q3HttpPGHRequest()
       
   268     { }
       
   269 
       
   270     void start( Q3Http * );
       
   271 };
       
   272 
       
   273 void Q3HttpPGHRequest::start( Q3Http *http )
       
   274 {
       
   275     header.setValue( QLatin1String("Host"), http->d->hostname );
       
   276     Q3HttpNormalRequest::start( http );
       
   277 }
       
   278 
       
   279 /****************************************************
       
   280  *
       
   281  * Q3HttpSetHostRequest
       
   282  *
       
   283  ****************************************************/
       
   284 
       
   285 class Q3HttpSetHostRequest : public Q3HttpRequest
       
   286 {
       
   287 public:
       
   288     Q3HttpSetHostRequest( const QString &h, Q_UINT16 p ) :
       
   289 	hostname(h), port(p)
       
   290     { }
       
   291 
       
   292     void start( Q3Http * );
       
   293 
       
   294     QIODevice* sourceDevice()
       
   295     { return 0; }
       
   296     QIODevice* destinationDevice()
       
   297     { return 0; }
       
   298 
       
   299 private:
       
   300     QString hostname;
       
   301     Q_UINT16 port;
       
   302 };
       
   303 
       
   304 void Q3HttpSetHostRequest::start( Q3Http *http )
       
   305 {
       
   306     http->d->hostname = hostname;
       
   307     http->d->port = port;
       
   308     http->finishedWithSuccess();
       
   309 }
       
   310 
       
   311 /****************************************************
       
   312  *
       
   313  * Q3HttpCloseRequest
       
   314  *
       
   315  ****************************************************/
       
   316 
       
   317 class Q3HttpCloseRequest : public Q3HttpRequest
       
   318 {
       
   319 public:
       
   320     Q3HttpCloseRequest()
       
   321     { }
       
   322     void start( Q3Http * );
       
   323 
       
   324     QIODevice* sourceDevice()
       
   325     { return 0; }
       
   326     QIODevice* destinationDevice()
       
   327     { return 0; }
       
   328 };
       
   329 
       
   330 void Q3HttpCloseRequest::start( Q3Http *http )
       
   331 {
       
   332     http->close();
       
   333 }
       
   334 
       
   335 /****************************************************
       
   336  *
       
   337  * Q3HttpHeader
       
   338  *
       
   339  ****************************************************/
       
   340 
       
   341 /*!
       
   342     \class Q3HttpHeader
       
   343     \brief The Q3HttpHeader class contains header information for HTTP.
       
   344 
       
   345     \compat
       
   346 
       
   347     In most cases you should use the more specialized derivatives of
       
   348     this class, Q3HttpResponseHeader and Q3HttpRequestHeader, rather
       
   349     than directly using Q3HttpHeader.
       
   350 
       
   351     Q3HttpHeader provides the HTTP header fields. A HTTP header field
       
   352     consists of a name followed by a colon, a single space, and the
       
   353     field value. (See RFC 1945.) Field names are case-insensitive. A
       
   354     typical header field looks like this:
       
   355     \snippet doc/src/snippets/code/src_qt3support_network_q3http.cpp 0
       
   356 
       
   357     In the API the header field name is called the "key" and the
       
   358     content is called the "value". You can get and set a header
       
   359     field's value by using its key with value() and setValue(), e.g.
       
   360     \snippet doc/src/snippets/code/src_qt3support_network_q3http.cpp 1
       
   361 
       
   362     Some fields are so common that getters and setters are provided
       
   363     for them as a convenient alternative to using \l value() and
       
   364     \l setValue(), e.g. contentLength() and contentType(),
       
   365     setContentLength() and setContentType().
       
   366 
       
   367     Each header key has a \e single value associated with it. If you
       
   368     set the value for a key which already exists the previous value
       
   369     will be discarded.
       
   370 
       
   371     \sa Q3HttpRequestHeader Q3HttpResponseHeader
       
   372 */
       
   373 
       
   374 /*!
       
   375     \fn int Q3HttpHeader::majorVersion() const
       
   376 
       
   377     Returns the major protocol-version of the HTTP header.
       
   378 */
       
   379 
       
   380 /*!
       
   381     \fn int Q3HttpHeader::minorVersion() const
       
   382 
       
   383     Returns the minor protocol-version of the HTTP header.
       
   384 */
       
   385 
       
   386 /*!
       
   387 	Constructs an empty HTTP header.
       
   388 */
       
   389 Q3HttpHeader::Q3HttpHeader()
       
   390     : valid( true )
       
   391 {
       
   392 }
       
   393 
       
   394 /*!
       
   395 	Constructs a copy of \a header.
       
   396 */
       
   397 Q3HttpHeader::Q3HttpHeader( const Q3HttpHeader& header )
       
   398     : valid( header.valid )
       
   399 {
       
   400     values = header.values;
       
   401 }
       
   402 
       
   403 /*!
       
   404     Constructs a HTTP header for \a str.
       
   405 
       
   406     This constructor parses the string \a str for header fields and
       
   407     adds this information. The \a str should consist of one or more
       
   408     "\r\n" delimited lines; each of these lines should have the format
       
   409     key, colon, space, value.
       
   410 */
       
   411 Q3HttpHeader::Q3HttpHeader( const QString& str )
       
   412     : valid( true )
       
   413 {
       
   414     parse( str );
       
   415 }
       
   416 
       
   417 /*!
       
   418     Destructor.
       
   419 */
       
   420 Q3HttpHeader::~Q3HttpHeader()
       
   421 {
       
   422 }
       
   423 
       
   424 /*!
       
   425     Assigns \a h and returns a reference to this http header.
       
   426 */
       
   427 Q3HttpHeader& Q3HttpHeader::operator=( const Q3HttpHeader& h )
       
   428 {
       
   429     values = h.values;
       
   430     valid = h.valid;
       
   431     return *this;
       
   432 }
       
   433 
       
   434 /*!
       
   435     Returns true if the HTTP header is valid; otherwise returns false.
       
   436 
       
   437     A Q3HttpHeader is invalid if it was created by parsing a malformed string.
       
   438 */
       
   439 bool Q3HttpHeader::isValid() const
       
   440 {
       
   441     return valid;
       
   442 }
       
   443 
       
   444 /*! \internal
       
   445     Parses the HTTP header string \a str for header fields and adds
       
   446     the keys/values it finds. If the string is not parsed successfully
       
   447     the Q3HttpHeader becomes \link isValid() invalid\endlink.
       
   448 
       
   449     Returns true if \a str was successfully parsed; otherwise returns false.
       
   450 
       
   451     \sa toString()
       
   452 */
       
   453 bool Q3HttpHeader::parse( const QString& str )
       
   454 {
       
   455     QStringList lst;
       
   456     int pos = str.find( QLatin1Char('\n') );
       
   457     if ( pos > 0 && str.at( pos - 1 ) == QLatin1Char('\r') )
       
   458 	lst = QStringList::split( QLatin1String("\r\n"), str.stripWhiteSpace(), false );
       
   459     else
       
   460 	lst = QStringList::split( QLatin1String("\n"), str.stripWhiteSpace(), false );
       
   461 
       
   462     if ( lst.isEmpty() )
       
   463 	return true;
       
   464 
       
   465     QStringList lines;
       
   466     QStringList::Iterator it = lst.begin();
       
   467     for( ; it != lst.end(); ++it ) {
       
   468 	if ( !(*it).isEmpty() ) {
       
   469 	    if ( (*it)[0].isSpace() ) {
       
   470 		if ( !lines.isEmpty() ) {
       
   471 		    lines.last() += QLatin1Char(' ');
       
   472 		    lines.last() += (*it).stripWhiteSpace();
       
   473 		}
       
   474 	    } else {
       
   475 		lines.append( (*it) );
       
   476 	    }
       
   477 	}
       
   478     }
       
   479 
       
   480     int number = 0;
       
   481     it = lines.begin();
       
   482     for( ; it != lines.end(); ++it ) {
       
   483 	if ( !parseLine( *it, number++ ) ) {
       
   484 	    valid = false;
       
   485 	    return false;
       
   486 	}
       
   487     }
       
   488     return true;
       
   489 }
       
   490 
       
   491 /*! \internal
       
   492 */
       
   493 void Q3HttpHeader::setValid( bool v )
       
   494 {
       
   495     valid = v;
       
   496 }
       
   497 
       
   498 /*!
       
   499     Returns the value for the entry with the given \a key. If no entry
       
   500     has this \a key, an empty string is returned.
       
   501 
       
   502     \sa setValue() removeValue() hasKey() keys()
       
   503 */
       
   504 QString Q3HttpHeader::value( const QString& key ) const
       
   505 {
       
   506     return values[ key.lower() ];
       
   507 }
       
   508 
       
   509 /*!
       
   510     Returns a list of the keys in the HTTP header.
       
   511 
       
   512     \sa hasKey()
       
   513 */
       
   514 QStringList Q3HttpHeader::keys() const
       
   515 {
       
   516     return values.keys();
       
   517 }
       
   518 
       
   519 /*!
       
   520     Returns true if the HTTP header has an entry with the given \a
       
   521     key; otherwise returns false.
       
   522 
       
   523     \sa value() setValue() keys()
       
   524 */
       
   525 bool Q3HttpHeader::hasKey( const QString& key ) const
       
   526 {
       
   527     return values.contains( key.lower() );
       
   528 }
       
   529 
       
   530 /*!
       
   531     Sets the value of the entry with the \a key to \a value.
       
   532 
       
   533     If no entry with \a key exists, a new entry with the given \a key
       
   534     and \a value is created. If an entry with the \a key already
       
   535     exists, its value is discarded and replaced with the given \a
       
   536     value.
       
   537 
       
   538     \sa value() hasKey() removeValue()
       
   539 */
       
   540 void Q3HttpHeader::setValue( const QString& key, const QString& value )
       
   541 {
       
   542     values[ key.lower() ] = value;
       
   543 }
       
   544 
       
   545 /*!
       
   546     Removes the entry with the key \a key from the HTTP header.
       
   547 
       
   548     \sa value() setValue()
       
   549 */
       
   550 void Q3HttpHeader::removeValue( const QString& key )
       
   551 {
       
   552     values.remove( key.lower() );
       
   553 }
       
   554 
       
   555 /*! \internal
       
   556     Parses the single HTTP header line \a line which has the format
       
   557     key, colon, space, value, and adds key/value to the headers. The
       
   558     linenumber is \a number. Returns true if the line was successfully
       
   559     parsed and the key/value added; otherwise returns false.
       
   560 
       
   561     \sa parse()
       
   562 */
       
   563 bool Q3HttpHeader::parseLine( const QString& line, int )
       
   564 {
       
   565     int i = line.find( QLatin1Char(':') );
       
   566     if ( i == -1 )
       
   567 	return false;
       
   568 
       
   569     values.insert( line.left( i ).stripWhiteSpace().lower(), line.mid( i + 1 ).stripWhiteSpace() );
       
   570 
       
   571     return true;
       
   572 }
       
   573 
       
   574 /*!
       
   575     Returns a string representation of the HTTP header.
       
   576 
       
   577     The string is suitable for use by the constructor that takes a
       
   578     QString. It consists of lines with the format: key, colon, space,
       
   579     value, "\r\n".
       
   580 */
       
   581 QString Q3HttpHeader::toString() const
       
   582 {
       
   583     if ( !isValid() )
       
   584 	return QLatin1String("");
       
   585 
       
   586     QString ret = QLatin1String("");
       
   587 
       
   588     QMap<QString,QString>::ConstIterator it = values.begin();
       
   589     for( ; it != values.end(); ++it )
       
   590 	ret += it.key() + QLatin1String(": ") + it.data() + QLatin1String("\r\n");
       
   591 
       
   592     return ret;
       
   593 }
       
   594 
       
   595 /*!
       
   596     Returns true if the header has an entry for the special HTTP
       
   597     header field \c content-length; otherwise returns false.
       
   598 
       
   599     \sa contentLength() setContentLength()
       
   600 */
       
   601 bool Q3HttpHeader::hasContentLength() const
       
   602 {
       
   603     return hasKey( QLatin1String("content-length") );
       
   604 }
       
   605 
       
   606 /*!
       
   607     Returns the value of the special HTTP header field \c
       
   608     content-length.
       
   609 
       
   610     \sa setContentLength() hasContentLength()
       
   611 */
       
   612 uint Q3HttpHeader::contentLength() const
       
   613 {
       
   614     return values[ QLatin1String("content-length") ].toUInt();
       
   615 }
       
   616 
       
   617 /*!
       
   618     Sets the value of the special HTTP header field \c content-length
       
   619     to \a len.
       
   620 
       
   621     \sa contentLength() hasContentLength()
       
   622 */
       
   623 void Q3HttpHeader::setContentLength( int len )
       
   624 {
       
   625     values[ QLatin1String("content-length") ] = QString::number( len );
       
   626 }
       
   627 
       
   628 /*!
       
   629     Returns true if the header has an entry for the special HTTP
       
   630     header field \c content-type; otherwise returns false.
       
   631 
       
   632     \sa contentType() setContentType()
       
   633 */
       
   634 bool Q3HttpHeader::hasContentType() const
       
   635 {
       
   636     return hasKey( QLatin1String("content-type") );
       
   637 }
       
   638 
       
   639 /*!
       
   640     Returns the value of the special HTTP header field \c content-type.
       
   641 
       
   642     \sa setContentType() hasContentType()
       
   643 */
       
   644 QString Q3HttpHeader::contentType() const
       
   645 {
       
   646     QString type = values[ QLatin1String("content-type") ];
       
   647     if ( type.isEmpty() )
       
   648 	return QString();
       
   649 
       
   650     int pos = type.find( QLatin1Char(';') );
       
   651     if ( pos == -1 )
       
   652 	return type;
       
   653 
       
   654     return type.left( pos ).stripWhiteSpace();
       
   655 }
       
   656 
       
   657 /*!
       
   658     Sets the value of the special HTTP header field \c content-type to
       
   659     \a type.
       
   660 
       
   661     \sa contentType() hasContentType()
       
   662 */
       
   663 void Q3HttpHeader::setContentType( const QString& type )
       
   664 {
       
   665     values[ QLatin1String("content-type") ] = type;
       
   666 }
       
   667 
       
   668 /****************************************************
       
   669  *
       
   670  * Q3HttpResponseHeader
       
   671  *
       
   672  ****************************************************/
       
   673 
       
   674 /*!
       
   675     \class Q3HttpResponseHeader
       
   676     \brief The Q3HttpResponseHeader class contains response header information for HTTP.
       
   677 
       
   678     \compat
       
   679 
       
   680     This class is used by the Q3Http class to report the header
       
   681     information that the client received from the server.
       
   682 
       
   683     HTTP responses have a status code that indicates the status of the
       
   684     response. This code is a 3-digit integer result code (for details
       
   685     see to RFC 1945). In addition to the status code, you can also
       
   686     specify a human-readable text that describes the reason for the
       
   687     code ("reason phrase"). This class allows you to get the status
       
   688     code and the reason phrase.
       
   689 
       
   690     \sa Q3HttpRequestHeader Q3Http
       
   691 */
       
   692 
       
   693 /*!
       
   694     Constructs an empty HTTP response header.
       
   695 */
       
   696 Q3HttpResponseHeader::Q3HttpResponseHeader()
       
   697 {
       
   698     setValid( false );
       
   699 }
       
   700 
       
   701 /*!
       
   702     Constructs a HTTP response header with the status code \a code,
       
   703     the reason phrase \a text and the protocol-version \a majorVer and
       
   704     \a minorVer.
       
   705 */
       
   706 Q3HttpResponseHeader::Q3HttpResponseHeader( int code, const QString& text, int majorVer, int minorVer )
       
   707     : Q3HttpHeader(), statCode( code ), reasonPhr( text ), majVer( majorVer ), minVer( minorVer )
       
   708 {
       
   709 }
       
   710 
       
   711 /*!
       
   712     Constructs a copy of \a header.
       
   713 */
       
   714 Q3HttpResponseHeader::Q3HttpResponseHeader( const Q3HttpResponseHeader& header )
       
   715     : Q3HttpHeader( header ), statCode( header.statCode ), reasonPhr( header.reasonPhr ), majVer( header.majVer ), minVer( header.minVer )
       
   716 {
       
   717 }
       
   718 
       
   719 /*!
       
   720     Constructs a HTTP response header from the string \a str. The
       
   721     string is parsed and the information is set. The \a str should
       
   722     consist of one or more "\r\n" delimited lines; the first line should be the
       
   723     status-line (format: HTTP-version, space, status-code, space,
       
   724     reason-phrase); each of remaining lines should have the format key, colon,
       
   725     space, value.
       
   726 */
       
   727 Q3HttpResponseHeader::Q3HttpResponseHeader( const QString& str )
       
   728     : Q3HttpHeader()
       
   729 {
       
   730     parse( str );
       
   731 }
       
   732 
       
   733 /*!
       
   734     Sets the status code to \a code, the reason phrase to \a text and
       
   735     the protocol-version to \a majorVer and \a minorVer.
       
   736 
       
   737     \sa statusCode() reasonPhrase() majorVersion() minorVersion()
       
   738 */
       
   739 void Q3HttpResponseHeader::setStatusLine( int code, const QString& text, int majorVer, int minorVer )
       
   740 {
       
   741     setValid( true );
       
   742     statCode = code;
       
   743     reasonPhr = text;
       
   744     majVer = majorVer;
       
   745     minVer = minorVer;
       
   746 }
       
   747 
       
   748 /*!
       
   749     Returns the status code of the HTTP response header.
       
   750 
       
   751     \sa reasonPhrase() majorVersion() minorVersion()
       
   752 */
       
   753 int Q3HttpResponseHeader::statusCode() const
       
   754 {
       
   755     return statCode;
       
   756 }
       
   757 
       
   758 /*!
       
   759     Returns the reason phrase of the HTTP response header.
       
   760 
       
   761     \sa statusCode() majorVersion() minorVersion()
       
   762 */
       
   763 QString Q3HttpResponseHeader::reasonPhrase() const
       
   764 {
       
   765     return reasonPhr;
       
   766 }
       
   767 
       
   768 /*!
       
   769     Returns the major protocol-version of the HTTP response header.
       
   770 
       
   771     \sa minorVersion() statusCode() reasonPhrase()
       
   772 */
       
   773 int Q3HttpResponseHeader::majorVersion() const
       
   774 {
       
   775     return majVer;
       
   776 }
       
   777 
       
   778 /*!
       
   779     Returns the minor protocol-version of the HTTP response header.
       
   780 
       
   781     \sa majorVersion() statusCode() reasonPhrase()
       
   782 */
       
   783 int Q3HttpResponseHeader::minorVersion() const
       
   784 {
       
   785     return minVer;
       
   786 }
       
   787 
       
   788 /*! \internal
       
   789 */
       
   790 bool Q3HttpResponseHeader::parseLine( const QString& line, int number )
       
   791 {
       
   792     if ( number != 0 )
       
   793 	return Q3HttpHeader::parseLine( line, number );
       
   794 
       
   795     QString l = line.simplifyWhiteSpace();
       
   796     if ( l.length() < 10 )
       
   797 	return false;
       
   798 
       
   799     if ( l.left( 5 ) == QLatin1String("HTTP/") && l[5].isDigit() && l[6] == QLatin1Char('.') &&
       
   800 	    l[7].isDigit() && l[8] == QLatin1Char(' ') && l[9].isDigit() ) {
       
   801 	majVer = l[5].latin1() - '0';
       
   802 	minVer = l[7].latin1() - '0';
       
   803 
       
   804 	int pos = l.find( QLatin1Char(' '), 9 );
       
   805 	if ( pos != -1 ) {
       
   806 	    reasonPhr = l.mid( pos + 1 );
       
   807 	    statCode = l.mid( 9, pos - 9 ).toInt();
       
   808 	} else {
       
   809 	    statCode = l.mid( 9 ).toInt();
       
   810 	    reasonPhr.clear();
       
   811 	}
       
   812     } else {
       
   813 	return false;
       
   814     }
       
   815 
       
   816     return true;
       
   817 }
       
   818 
       
   819 /*! \reimp
       
   820 */
       
   821 QString Q3HttpResponseHeader::toString() const
       
   822 {
       
   823     QString ret( QLatin1String("HTTP/%1.%2 %3 %4\r\n%5\r\n") );
       
   824     return ret.arg( majVer ).arg ( minVer ).arg( statCode ).arg( reasonPhr ).arg( Q3HttpHeader::toString() );
       
   825 }
       
   826 
       
   827 /****************************************************
       
   828  *
       
   829  * Q3HttpRequestHeader
       
   830  *
       
   831  ****************************************************/
       
   832 
       
   833 /*!
       
   834     \class Q3HttpRequestHeader
       
   835     \brief The Q3HttpRequestHeader class contains request header information for
       
   836     HTTP.
       
   837 
       
   838     \compat
       
   839 
       
   840     This class is used in the Q3Http class to report the header
       
   841     information if the client requests something from the server.
       
   842 
       
   843     HTTP requests have a method which describes the request's action.
       
   844     The most common requests are "GET" and "POST". In addition to the
       
   845     request method the header also includes a request-URI to specify
       
   846     the location for the method to use.
       
   847 
       
   848     The method, request-URI and protocol-version can be set using a
       
   849     constructor or later using setRequest(). The values can be
       
   850     obtained using method(), path(), majorVersion() and
       
   851     minorVersion().
       
   852 
       
   853     This class is a Q3HttpHeader subclass so that class's functions,
       
   854     e.g. \link Q3HttpHeader::setValue() setValue()\endlink, \link
       
   855     Q3HttpHeader::value() value()\endlink, etc. are also available.
       
   856 
       
   857     \sa Q3HttpResponseHeader Q3Http
       
   858 */
       
   859 
       
   860 /*!
       
   861     Constructs an empty HTTP request header.
       
   862 */
       
   863 Q3HttpRequestHeader::Q3HttpRequestHeader()
       
   864     : Q3HttpHeader()
       
   865 {
       
   866     setValid( false );
       
   867 }
       
   868 
       
   869 /*!
       
   870     Constructs a HTTP request header for the method \a method, the
       
   871     request-URI \a path and the protocol-version \a majorVer and \a minorVer.
       
   872 */
       
   873 Q3HttpRequestHeader::Q3HttpRequestHeader( const QString& method, const QString& path, int majorVer, int minorVer )
       
   874     : Q3HttpHeader(), m( method ), p( path ), majVer( majorVer ), minVer( minorVer )
       
   875 {
       
   876 }
       
   877 
       
   878 /*!
       
   879     Constructs a copy of \a header.
       
   880 */
       
   881 Q3HttpRequestHeader::Q3HttpRequestHeader( const Q3HttpRequestHeader& header )
       
   882     : Q3HttpHeader( header ), m( header.m ), p( header.p ), majVer( header.majVer ), minVer( header.minVer )
       
   883 {
       
   884 }
       
   885 
       
   886 /*!
       
   887     Constructs a HTTP request header from the string \a str. The \a
       
   888     str should consist of one or more "\r\n" delimited lines; the first line
       
   889     should be the request-line (format: method, space, request-URI, space
       
   890     HTTP-version); each of the remaining lines should have the format key,
       
   891     colon, space, value.
       
   892 */
       
   893 Q3HttpRequestHeader::Q3HttpRequestHeader( const QString& str )
       
   894     : Q3HttpHeader()
       
   895 {
       
   896     parse( str );
       
   897 }
       
   898 
       
   899 /*!
       
   900     This function sets the request method to \a method, the
       
   901     request-URI to \a path and the protocol-version to \a majorVer and
       
   902     \a minorVer.
       
   903 
       
   904     \sa method() path() majorVersion() minorVersion()
       
   905 */
       
   906 void Q3HttpRequestHeader::setRequest( const QString& method, const QString& path, int majorVer, int minorVer )
       
   907 {
       
   908     setValid( true );
       
   909     m = method;
       
   910     p = path;
       
   911     majVer = majorVer;
       
   912     minVer = minorVer;
       
   913 }
       
   914 
       
   915 /*!
       
   916     Returns the method of the HTTP request header.
       
   917 
       
   918     \sa path() majorVersion() minorVersion() setRequest()
       
   919 */
       
   920 QString Q3HttpRequestHeader::method() const
       
   921 {
       
   922     return m;
       
   923 }
       
   924 
       
   925 /*!
       
   926     Returns the request-URI of the HTTP request header.
       
   927 
       
   928     \sa method() majorVersion() minorVersion() setRequest()
       
   929 */
       
   930 QString Q3HttpRequestHeader::path() const
       
   931 {
       
   932     return p;
       
   933 }
       
   934 
       
   935 /*!
       
   936     Returns the major protocol-version of the HTTP request header.
       
   937 
       
   938     \sa minorVersion() method() path() setRequest()
       
   939 */
       
   940 int Q3HttpRequestHeader::majorVersion() const
       
   941 {
       
   942     return majVer;
       
   943 }
       
   944 
       
   945 /*!
       
   946     Returns the minor protocol-version of the HTTP request header.
       
   947 
       
   948     \sa majorVersion() method() path() setRequest()
       
   949 */
       
   950 int Q3HttpRequestHeader::minorVersion() const
       
   951 {
       
   952     return minVer;
       
   953 }
       
   954 
       
   955 /*! \internal
       
   956 */
       
   957 bool Q3HttpRequestHeader::parseLine( const QString& line, int number )
       
   958 {
       
   959     if ( number != 0 )
       
   960 	return Q3HttpHeader::parseLine( line, number );
       
   961 
       
   962     QStringList lst = QStringList::split( QLatin1String(" "), line.simplifyWhiteSpace() );
       
   963     if ( lst.count() > 0 ) {
       
   964 	m = lst[0];
       
   965 	if ( lst.count() > 1 ) {
       
   966 	    p = lst[1];
       
   967 	    if ( lst.count() > 2 ) {
       
   968 		QString v = lst[2];
       
   969 		if ( v.length() >= 8 && v.left( 5 ) == QLatin1String("HTTP/") &&
       
   970 			v[5].isDigit() && v[6] == QLatin1Char('.') && v[7].isDigit() ) {
       
   971 		    majVer = v[5].latin1() - '0';
       
   972 		    minVer = v[7].latin1() - '0';
       
   973 		    return true;
       
   974 		}
       
   975 	    }
       
   976 	}
       
   977     }
       
   978 
       
   979     return false;
       
   980 }
       
   981 
       
   982 /*! \reimp
       
   983 */
       
   984 QString Q3HttpRequestHeader::toString() const
       
   985 {
       
   986     QString first( QLatin1String("%1 %2"));
       
   987     QString last(QLatin1String(" HTTP/%3.%4\r\n%5\r\n") );
       
   988     return first.arg( m ).arg( p ) +
       
   989 	last.arg( majVer ).arg( minVer ).arg( Q3HttpHeader::toString());
       
   990 }
       
   991 
       
   992 
       
   993 /****************************************************
       
   994  *
       
   995  * Q3Http
       
   996  *
       
   997  ****************************************************/
       
   998 /*!
       
   999     \class Q3Http
       
  1000     \brief The Q3Http class provides an implementation of the HTTP protocol.
       
  1001 
       
  1002     \compat
       
  1003 
       
  1004     This class provides two different interfaces: one is the
       
  1005     Q3NetworkProtocol interface that allows you to use HTTP through the
       
  1006     QUrlOperator abstraction. The other is a direct interface to HTTP
       
  1007     that allows you to have more control over the requests and that
       
  1008     allows you to access the response header fields.
       
  1009 
       
  1010     Don't mix the two interfaces, since the behavior is not
       
  1011     well-defined.
       
  1012 
       
  1013     If you want to use Q3Http with the Q3NetworkProtocol interface, you
       
  1014     do not use it directly, but rather through a QUrlOperator, for
       
  1015     example:
       
  1016 
       
  1017     \snippet doc/src/snippets/code/src_qt3support_network_q3http.cpp 2
       
  1018 
       
  1019     This code will only work if the Q3Http class is registered; to
       
  1020     register the class, you must call q3InitNetworkProtocols() before
       
  1021     using a QUrlOperator with HTTP.
       
  1022 
       
  1023     The Q3NetworkProtocol interface for HTTP only supports the
       
  1024     operations operationGet() and operationPut(), i.e.
       
  1025     QUrlOperator::get() and QUrlOperator::put(), if you use it with a
       
  1026     QUrlOperator.
       
  1027 
       
  1028     The rest of this descrption describes the direct interface to
       
  1029     HTTP.
       
  1030 
       
  1031     The class works asynchronously, so there are no blocking
       
  1032     functions. If an operation cannot be executed immediately, the
       
  1033     function will still return straight away and the operation will be
       
  1034     scheduled for later execution. The results of scheduled operations
       
  1035     are reported via signals. This approach depends on the event loop
       
  1036     being in operation.
       
  1037 
       
  1038     The operations that can be scheduled (they are called "requests"
       
  1039     in the rest of the documentation) are the following: setHost(),
       
  1040     get(), post(), head() and request().
       
  1041 
       
  1042     All of these requests return a unique identifier that allows you
       
  1043     to keep track of the request that is currently executed. When the
       
  1044     execution of a request starts, the requestStarted() signal with
       
  1045     the identifier is emitted and when the request is finished, the
       
  1046     requestFinished() signal is emitted with the identifier and a bool
       
  1047     that indicates if the request finished with an error.
       
  1048 
       
  1049     To make an HTTP request you must set up suitable HTTP headers. The
       
  1050     following example demonstrates, how to request the main HTML page
       
  1051     from the Qt website (i.e. the URL \c http://qt.nokia.com/index.html):
       
  1052 
       
  1053     \snippet doc/src/snippets/code/src_qt3support_network_q3http.cpp 3
       
  1054 
       
  1055     For the common HTTP requests \c GET, \c POST and \c HEAD, Q3Http
       
  1056     provides the convenience functions get(), post() and head(). They
       
  1057     already use a reasonable header and if you don't have to set
       
  1058     special header fields, they are easier to use. The above example
       
  1059     can also be written as:
       
  1060 
       
  1061     \snippet doc/src/snippets/code/src_qt3support_network_q3http.cpp 4
       
  1062 
       
  1063     For this example the following sequence of signals is emitted
       
  1064     (with small variations, depending on network traffic, etc.):
       
  1065 
       
  1066     \snippet doc/src/snippets/code/src_qt3support_network_q3http.cpp 5
       
  1067 
       
  1068     The dataSendProgress() and dataReadProgress() signals in the above
       
  1069     example are useful if you want to show a \link QProgressBar
       
  1070     progress bar\endlink to inform the user about the progress of the
       
  1071     download. The second argument is the total size of data. In
       
  1072     certain cases it is not possible to know the total amount in
       
  1073     advance, in which case the second argument is 0. (If you connect
       
  1074     to a QProgressBar a total of 0 results in a busy indicator.)
       
  1075 
       
  1076     When the response header is read, it is reported with the
       
  1077     responseHeaderReceived() signal.
       
  1078 
       
  1079     The readyRead() signal tells you that there is data ready to be
       
  1080     read. The amount of data can then be queried with the
       
  1081     bytesAvailable() function and it can be read with the readBlock()
       
  1082     or readAll() functions.
       
  1083 
       
  1084     If an error occurs during the execution of one of the commands in
       
  1085     a sequence of commands, all the pending commands (i.e. scheduled,
       
  1086     but not yet executed commands) are cleared and no signals are
       
  1087     emitted for them.
       
  1088 
       
  1089     For example, if you have the following sequence of reqeusts
       
  1090 
       
  1091     \snippet doc/src/snippets/code/src_qt3support_network_q3http.cpp 6
       
  1092 
       
  1093     and the get() request fails because the host lookup fails, then
       
  1094     the post() request is never executed and the signals would look
       
  1095     like this:
       
  1096 
       
  1097     \snippet doc/src/snippets/code/src_qt3support_network_q3http.cpp 7
       
  1098 
       
  1099     You can then get details about the error with the error() and
       
  1100     errorString() functions. Note that only unexpected behaviour, like
       
  1101     network failure is considered as an error. If the server response
       
  1102     contains an error status, like a 404 response, this is reported as
       
  1103     a normal response case. So you should always check the \link
       
  1104     Q3HttpResponseHeader::statusCode() status code \endlink of the
       
  1105     response header.
       
  1106 
       
  1107     The functions currentId() and currentRequest() provide more
       
  1108     information about the currently executing request.
       
  1109 
       
  1110     The functions hasPendingRequests() and clearPendingRequests()
       
  1111     allow you to query and clear the list of pending requests.
       
  1112 
       
  1113     \sa Q3NetworkProtocol, Q3UrlOperator, Q3Ftp
       
  1114 */
       
  1115 
       
  1116 /*!
       
  1117     Constructs a Q3Http object.
       
  1118 */
       
  1119 Q3Http::Q3Http()
       
  1120 {
       
  1121     init();
       
  1122 }
       
  1123 
       
  1124 /*!
       
  1125     Constructs a Q3Http object. The parameters \a parent and \a name
       
  1126     are passed on to the QObject constructor.
       
  1127 */
       
  1128 Q3Http::Q3Http( QObject* parent, const char* name )
       
  1129 {
       
  1130     if ( parent )
       
  1131 	parent->insertChild( this );
       
  1132     setName( name );
       
  1133     init();
       
  1134 }
       
  1135 
       
  1136 /*!
       
  1137     Constructs a Q3Http object. Subsequent requests are done by
       
  1138     connecting to the server \a hostname on port \a port. The
       
  1139     parameters \a parent and \a name are passed on to the QObject
       
  1140     constructor.
       
  1141 
       
  1142     \sa setHost()
       
  1143 */
       
  1144 Q3Http::Q3Http( const QString &hostname, Q_UINT16 port, QObject* parent, const char* name )
       
  1145 {
       
  1146     if ( parent )
       
  1147 	parent->insertChild( this );
       
  1148     setName( name );
       
  1149     init();
       
  1150 
       
  1151     d->hostname = hostname;
       
  1152     d->port = port;
       
  1153 }
       
  1154 
       
  1155 void Q3Http::init()
       
  1156 {
       
  1157     bytesRead = 0;
       
  1158     d = new Q3HttpPrivate;
       
  1159     d->errorString = QHttp::tr( "Unknown error" );
       
  1160 
       
  1161     connect( &d->socket, SIGNAL(connected()),
       
  1162 	    this, SLOT(slotConnected()) );
       
  1163     connect( &d->socket, SIGNAL(connectionClosed()),
       
  1164 	    this, SLOT(slotClosed()) );
       
  1165     connect( &d->socket, SIGNAL(delayedCloseFinished()),
       
  1166 	    this, SLOT(slotClosed()) );
       
  1167     connect( &d->socket, SIGNAL(readyRead()),
       
  1168 	    this, SLOT(slotReadyRead()) );
       
  1169     connect( &d->socket, SIGNAL(error(int)),
       
  1170 	    this, SLOT(slotError(int)) );
       
  1171     connect( &d->socket, SIGNAL(bytesWritten(int)),
       
  1172 	    this, SLOT(slotBytesWritten(int)) );
       
  1173 
       
  1174     d->idleTimer = startTimer( 0 );
       
  1175 }
       
  1176 
       
  1177 /*!
       
  1178     Destroys the Q3Http object. If there is an open connection, it is
       
  1179     closed.
       
  1180 */
       
  1181 Q3Http::~Q3Http()
       
  1182 {
       
  1183     abort();
       
  1184     delete d;
       
  1185 }
       
  1186 
       
  1187 /*!
       
  1188     \enum Q3Http::State
       
  1189 
       
  1190     This enum is used to specify the state the client is in:
       
  1191 
       
  1192     \value Unconnected There is no connection to the host.
       
  1193     \value HostLookup A host name lookup is in progress.
       
  1194     \value Connecting An attempt to connect to the host is in progress.
       
  1195     \value Sending The client is sending its request to the server.
       
  1196     \value Reading The client's request has been sent and the client
       
  1197     is reading the server's response.
       
  1198     \value Connected The connection to the host is open, but the client is
       
  1199     neither sending a request, nor waiting for a response.
       
  1200     \value Closing The connection is closing down, but is not yet
       
  1201     closed. (The state will be \c Unconnected when the connection is
       
  1202     closed.)
       
  1203 
       
  1204     \sa stateChanged() state()
       
  1205 */
       
  1206 
       
  1207 /*!  \enum Q3Http::Error
       
  1208 
       
  1209     This enum identifies the error that occurred.
       
  1210 
       
  1211     \value NoError No error occurred.
       
  1212     \value HostNotFound The host name lookup failed.
       
  1213     \value ConnectionRefused The server refused the connection.
       
  1214     \value UnexpectedClose The server closed the connection unexpectedly.
       
  1215     \value InvalidResponseHeader The server sent an invalid response header.
       
  1216     \value WrongContentLength The client could not read the content correctly
       
  1217     because an error with respect to the content length occurred.
       
  1218     \value Aborted The request was aborted with abort().
       
  1219     \value UnknownError An error other than those specified above
       
  1220     occurred.
       
  1221 
       
  1222     \sa error()
       
  1223 */
       
  1224 
       
  1225 /*!
       
  1226     \fn void Q3Http::stateChanged( int state )
       
  1227 
       
  1228     This signal is emitted when the state of the Q3Http object changes.
       
  1229     The argument \a state is the new state of the connection; it is
       
  1230     one of the \l State values.
       
  1231 
       
  1232     This usually happens when a request is started, but it can also
       
  1233     happen when the server closes the connection or when a call to
       
  1234     closeConnection() succeeded.
       
  1235 
       
  1236     \sa get() post() head() request() closeConnection() state() State
       
  1237 */
       
  1238 
       
  1239 /*!
       
  1240     \fn void Q3Http::responseHeaderReceived( const Q3HttpResponseHeader& resp )
       
  1241 
       
  1242     This signal is emitted when the HTTP header of a server response
       
  1243     is available. The header is passed in \a resp.
       
  1244 
       
  1245     \sa get() post() head() request() readyRead()
       
  1246 */
       
  1247 
       
  1248 /*!
       
  1249     \fn void Q3Http::readyRead( const Q3HttpResponseHeader& resp )
       
  1250 
       
  1251     This signal is emitted when there is new response data to read.
       
  1252 
       
  1253     If you specified a device in the request where the data should be
       
  1254     written to, then this signal is \e not emitted; instead the data
       
  1255     is written directly to the device.
       
  1256 
       
  1257     The response header is passed in \a resp.
       
  1258 
       
  1259     You can read the data with the readAll() or readBlock() functions
       
  1260 
       
  1261     This signal is useful if you want to process the data in chunks as
       
  1262     soon as it becomes available. If you are only interested in the
       
  1263     complete data, just connect to the requestFinished() signal and
       
  1264     read the data then instead.
       
  1265 
       
  1266     \sa get() post() request() readAll() readBlock() bytesAvailable()
       
  1267 */
       
  1268 
       
  1269 /*!
       
  1270     \fn void Q3Http::dataSendProgress( int done, int total )
       
  1271 
       
  1272     This signal is emitted when this object sends data to a HTTP
       
  1273     server to inform it about the progress of the upload.
       
  1274 
       
  1275     \a done is the amount of data that has already arrived and \a
       
  1276     total is the total amount of data. It is possible that the total
       
  1277     amount of data that should be transferred cannot be determined, in
       
  1278     which case \a total is 0.(If you connect to a QProgressBar, the
       
  1279     progress bar shows a busy indicator if the total is 0).
       
  1280 
       
  1281     \warning \a done and \a total are not necessarily the size in
       
  1282     bytes, since for large files these values might need to be
       
  1283     "scaled" to avoid overflow.
       
  1284 
       
  1285     \sa dataReadProgress() post() request() QProgressBar::setValue()
       
  1286 */
       
  1287 
       
  1288 /*!
       
  1289     \fn void Q3Http::dataReadProgress( int done, int total )
       
  1290 
       
  1291     This signal is emitted when this object reads data from a HTTP
       
  1292     server to indicate the current progress of the download.
       
  1293 
       
  1294     \a done is the amount of data that has already arrived and \a
       
  1295     total is the total amount of data. It is possible that the total
       
  1296     amount of data that should be transferred cannot be determined, in
       
  1297     which case \a total is 0.(If you connect to a QProgressBar, the
       
  1298     progress bar shows a busy indicator if the total is 0).
       
  1299 
       
  1300     \warning \a done and \a total are not necessarily the size in
       
  1301     bytes, since for large files these values might need to be
       
  1302     "scaled" to avoid overflow.
       
  1303 
       
  1304     \sa dataSendProgress() get() post() request() QProgressBar::setValue()
       
  1305 */
       
  1306 
       
  1307 /*!
       
  1308     \fn void Q3Http::requestStarted( int id )
       
  1309 
       
  1310     This signal is emitted when processing the request identified by
       
  1311     \a id starts.
       
  1312 
       
  1313     \sa requestFinished() done()
       
  1314 */
       
  1315 
       
  1316 /*!
       
  1317     \fn void Q3Http::requestFinished( int id, bool error )
       
  1318 
       
  1319     This signal is emitted when processing the request identified by
       
  1320     \a id has finished. \a error is true if an error occurred during
       
  1321     the processing; otherwise \a error is false.
       
  1322 
       
  1323     \sa requestStarted() done() error() errorString()
       
  1324 */
       
  1325 
       
  1326 /*!
       
  1327     \fn void Q3Http::done( bool error )
       
  1328 
       
  1329     This signal is emitted when the last pending request has finished;
       
  1330     (it is emitted after the last request's requestFinished() signal).
       
  1331     \a error is true if an error occurred during the processing;
       
  1332     otherwise \a error is false.
       
  1333 
       
  1334     \sa requestFinished() error() errorString()
       
  1335 */
       
  1336 
       
  1337 /*!
       
  1338     Aborts the current request and deletes all scheduled requests.
       
  1339 
       
  1340     For the current request, the requestFinished() signal with the \c
       
  1341     error argument \c true is emitted. For all other requests that are
       
  1342     affected by the abort(), no signals are emitted.
       
  1343 
       
  1344     Since this slot also deletes the scheduled requests, there are no
       
  1345     requests left and the done() signal is emitted (with the \c error
       
  1346     argument \c true).
       
  1347 
       
  1348     \sa clearPendingRequests()
       
  1349 */
       
  1350 void Q3Http::abort()
       
  1351 {
       
  1352     Q3HttpRequest *r = d->pending.getFirst();
       
  1353     if ( r == 0 )
       
  1354 	return;
       
  1355 
       
  1356     finishedWithError( QHttp::tr("Request aborted"), Aborted );
       
  1357     clearPendingRequests();
       
  1358     d->socket.clearPendingData();
       
  1359     close();
       
  1360 }
       
  1361 
       
  1362 /*!
       
  1363     Returns the number of bytes that can be read from the response
       
  1364     content at the moment.
       
  1365 
       
  1366     \sa get() post() request() readyRead() readBlock() readAll()
       
  1367 */
       
  1368 Q_ULONG Q3Http::bytesAvailable() const
       
  1369 {
       
  1370 #if defined(Q3HTTP_DEBUG)
       
  1371     qDebug( "Q3Http::bytesAvailable(): %d bytes", (int)d->rba.size() );
       
  1372 #endif
       
  1373     return d->rba.size();
       
  1374 }
       
  1375 
       
  1376 /*!
       
  1377     Reads \a maxlen bytes from the response content into \a data and
       
  1378     returns the number of bytes read. Returns -1 if an error occurred.
       
  1379 
       
  1380     \sa get() post() request() readyRead() bytesAvailable() readAll()
       
  1381 */
       
  1382 Q_LONG Q3Http::readBlock( char *data, Q_ULONG maxlen )
       
  1383 {
       
  1384     if ( data == 0 && maxlen != 0 ) {
       
  1385 #if defined(QT_CHECK_NULL)
       
  1386 	qWarning( "Q3Http::readBlock: Null pointer error" );
       
  1387 #endif
       
  1388 	return -1;
       
  1389     }
       
  1390     if ( maxlen >= (Q_ULONG)d->rba.size() )
       
  1391 	maxlen = d->rba.size();
       
  1392     d->rba.consumeBytes( maxlen, data );
       
  1393 
       
  1394     d->bytesDone += maxlen;
       
  1395 #if defined(Q3HTTP_DEBUG)
       
  1396     qDebug( "Q3Http::readBlock(): read %d bytes (%d bytes done)", (int)maxlen, d->bytesDone );
       
  1397 #endif
       
  1398     return maxlen;
       
  1399 }
       
  1400 
       
  1401 /*!
       
  1402     Reads all the bytes from the response content and returns them.
       
  1403 
       
  1404     \sa get() post() request() readyRead() bytesAvailable() readBlock()
       
  1405 */
       
  1406 QByteArray Q3Http::readAll()
       
  1407 {
       
  1408     Q_ULONG avail = bytesAvailable();
       
  1409     QByteArray tmp( avail );
       
  1410     Q_LONG read = readBlock( tmp.data(), avail );
       
  1411     tmp.resize( read );
       
  1412     return tmp;
       
  1413 }
       
  1414 
       
  1415 /*!
       
  1416     Returns the identifier of the HTTP request being executed or 0 if
       
  1417     there is no request being executed (i.e. they've all finished).
       
  1418 
       
  1419     \sa currentRequest()
       
  1420 */
       
  1421 int Q3Http::currentId() const
       
  1422 {
       
  1423     Q3HttpRequest *r = d->pending.getFirst();
       
  1424     if ( r == 0 )
       
  1425 	return 0;
       
  1426     return r->id;
       
  1427 }
       
  1428 
       
  1429 /*!
       
  1430     Returns the request header of the HTTP request being executed. If
       
  1431     the request is one issued by setHost() or closeConnection(), it
       
  1432     returns an invalid request header, i.e.
       
  1433     Q3HttpRequestHeader::isValid() returns false.
       
  1434 
       
  1435     \sa currentId()
       
  1436 */
       
  1437 Q3HttpRequestHeader Q3Http::currentRequest() const
       
  1438 {
       
  1439     Q3HttpRequest *r = d->pending.getFirst();
       
  1440     if ( r != 0 && r->hasRequestHeader() )
       
  1441 	return r->requestHeader();
       
  1442     return Q3HttpRequestHeader();
       
  1443 }
       
  1444 
       
  1445 /*!
       
  1446     Returns the QIODevice pointer that is used as the data source of the HTTP
       
  1447     request being executed. If there is no current request or if the request
       
  1448     does not use an IO device as the data source, this function returns 0.
       
  1449 
       
  1450     This function can be used to delete the QIODevice in the slot connected to
       
  1451     the requestFinished() signal.
       
  1452 
       
  1453     \sa currentDestinationDevice() post() request()
       
  1454 */
       
  1455 QIODevice* Q3Http::currentSourceDevice() const
       
  1456 {
       
  1457     Q3HttpRequest *r = d->pending.getFirst();
       
  1458     if ( !r )
       
  1459 	return 0;
       
  1460     return r->sourceDevice();
       
  1461 }
       
  1462 
       
  1463 /*!
       
  1464     Returns the QIODevice pointer that is used as to store the data of the HTTP
       
  1465     request being executed. If there is no current request or if the request
       
  1466     does not store the data to an IO device, this function returns 0.
       
  1467 
       
  1468     This function can be used to delete the QIODevice in the slot connected to
       
  1469     the requestFinished() signal.
       
  1470 
       
  1471     \sa get() post() request()
       
  1472 */
       
  1473 QIODevice* Q3Http::currentDestinationDevice() const
       
  1474 {
       
  1475     Q3HttpRequest *r = d->pending.getFirst();
       
  1476     if ( !r )
       
  1477 	return 0;
       
  1478     return r->destinationDevice();
       
  1479 }
       
  1480 
       
  1481 /*!
       
  1482     Returns true if there are any requests scheduled that have not yet
       
  1483     been executed; otherwise returns false.
       
  1484 
       
  1485     The request that is being executed is \e not considered as a
       
  1486     scheduled request.
       
  1487 
       
  1488     \sa clearPendingRequests() currentId() currentRequest()
       
  1489 */
       
  1490 bool Q3Http::hasPendingRequests() const
       
  1491 {
       
  1492     return d->pending.count() > 1;
       
  1493 }
       
  1494 
       
  1495 /*!
       
  1496     Deletes all pending requests from the list of scheduled requests.
       
  1497     This does not affect the request that is being executed. If
       
  1498     you want to stop this as well, use abort().
       
  1499 
       
  1500     \sa hasPendingRequests() abort()
       
  1501 */
       
  1502 void Q3Http::clearPendingRequests()
       
  1503 {
       
  1504     Q3HttpRequest *r = 0;
       
  1505     if ( d->pending.count() > 0 )
       
  1506 	r = d->pending.take( 0 );
       
  1507     d->pending.clear();
       
  1508     if ( r )
       
  1509 	d->pending.append( r );
       
  1510 }
       
  1511 
       
  1512 /*!
       
  1513     Sets the HTTP server that is used for requests to \a hostname on
       
  1514     port \a port.
       
  1515 
       
  1516     The function does not block and returns immediately. The request
       
  1517     is scheduled, and its execution is performed asynchronously. The
       
  1518     function returns a unique identifier which is passed by
       
  1519     requestStarted() and requestFinished().
       
  1520 
       
  1521     When the request is started the requestStarted() signal is
       
  1522     emitted. When it is finished the requestFinished() signal is
       
  1523     emitted.
       
  1524 
       
  1525     \sa get() post() head() request() requestStarted() requestFinished() done()
       
  1526 */
       
  1527 int Q3Http::setHost(const QString &hostname, Q_UINT16 port )
       
  1528 {
       
  1529     return addRequest( new Q3HttpSetHostRequest( hostname, port ) );
       
  1530 }
       
  1531 
       
  1532 /*!
       
  1533     Sends a get request for \a path to the server set by setHost() or
       
  1534     as specified in the constructor.
       
  1535 
       
  1536     \a path must be an absolute path like \c /index.html or an
       
  1537     absolute URI like \c http://example.com/index.html.
       
  1538 
       
  1539     If the IO device \a to is 0 the readyRead() signal is emitted
       
  1540     every time new content data is available to read.
       
  1541 
       
  1542     If the IO device \a to is not 0, the content data of the response
       
  1543     is written directly to the device. Make sure that the \a to
       
  1544     pointer is valid for the duration of the operation (it is safe to
       
  1545     delete it when the requestFinished() signal is emitted).
       
  1546 
       
  1547     The function does not block and returns immediately. The request
       
  1548     is scheduled, and its execution is performed asynchronously. The
       
  1549     function returns a unique identifier which is passed by
       
  1550     requestStarted() and requestFinished().
       
  1551 
       
  1552     When the request is started the requestStarted() signal is
       
  1553     emitted. When it is finished the requestFinished() signal is
       
  1554     emitted.
       
  1555 
       
  1556     \sa setHost() post() head() request() requestStarted() requestFinished() done()
       
  1557 */
       
  1558 int Q3Http::get( const QString& path, QIODevice* to )
       
  1559 {
       
  1560     Q3HttpRequestHeader header( QLatin1String("GET"), path );
       
  1561     header.setValue( QLatin1String("Connection"), QLatin1String("Keep-Alive") );
       
  1562     return addRequest( new Q3HttpPGHRequest( header, (QIODevice*)0, to ) );
       
  1563 }
       
  1564 
       
  1565 /*!
       
  1566     Sends a post request for \a path to the server set by setHost() or
       
  1567     as specified in the constructor.
       
  1568 
       
  1569     \a path must be an absolute path like \c /index.html or an
       
  1570     absolute URI like \c http://example.com/index.html.
       
  1571 
       
  1572     The incoming data comes via the \a data IO device.
       
  1573 
       
  1574     If the IO device \a to is 0 the readyRead() signal is emitted
       
  1575     every time new content data is available to read.
       
  1576 
       
  1577     If the IO device \a to is not 0, the content data of the response
       
  1578     is written directly to the device. Make sure that the \a to
       
  1579     pointer is valid for the duration of the operation (it is safe to
       
  1580     delete it when the requestFinished() signal is emitted).
       
  1581 
       
  1582     The function does not block and returns immediately. The request
       
  1583     is scheduled, and its execution is performed asynchronously. The
       
  1584     function returns a unique identifier which is passed by
       
  1585     requestStarted() and requestFinished().
       
  1586 
       
  1587     When the request is started the requestStarted() signal is
       
  1588     emitted. When it is finished the requestFinished() signal is
       
  1589     emitted.
       
  1590 
       
  1591     \sa setHost() get() head() request() requestStarted() requestFinished() done()
       
  1592 */
       
  1593 int Q3Http::post( const QString& path, QIODevice* data, QIODevice* to  )
       
  1594 {
       
  1595     Q3HttpRequestHeader header( QLatin1String("POST"), path );
       
  1596     header.setValue( QLatin1String("Connection"), QLatin1String("Keep-Alive") );
       
  1597     return addRequest( new Q3HttpPGHRequest( header, data, to ) );
       
  1598 }
       
  1599 
       
  1600 /*!
       
  1601     \overload
       
  1602 
       
  1603     \a data is used as the content data of the HTTP request.
       
  1604 */
       
  1605 int Q3Http::post( const QString& path, const QByteArray& data, QIODevice* to )
       
  1606 {
       
  1607     Q3HttpRequestHeader header( QLatin1String("POST"), path );
       
  1608     header.setValue( QLatin1String("Connection"), QLatin1String("Keep-Alive") );
       
  1609     return addRequest( new Q3HttpPGHRequest( header, new QByteArray(data), to ) );
       
  1610 }
       
  1611 
       
  1612 /*!
       
  1613     Sends a header request for \a path to the server set by setHost()
       
  1614     or as specified in the constructor.
       
  1615 
       
  1616     \a path must be an absolute path like \c /index.html or an
       
  1617     absolute URI like \c http://example.com/index.html.
       
  1618 
       
  1619     The function does not block and returns immediately. The request
       
  1620     is scheduled, and its execution is performed asynchronously. The
       
  1621     function returns a unique identifier which is passed by
       
  1622     requestStarted() and requestFinished().
       
  1623 
       
  1624     When the request is started the requestStarted() signal is
       
  1625     emitted. When it is finished the requestFinished() signal is
       
  1626     emitted.
       
  1627 
       
  1628     \sa setHost() get() post() request() requestStarted() requestFinished() done()
       
  1629 */
       
  1630 int Q3Http::head( const QString& path )
       
  1631 {
       
  1632     Q3HttpRequestHeader header( QLatin1String("HEAD"), path );
       
  1633     header.setValue( QLatin1String("Connection"), QLatin1String("Keep-Alive") );
       
  1634     return addRequest( new Q3HttpPGHRequest( header, (QIODevice*)0, 0 ) );
       
  1635 }
       
  1636 
       
  1637 /*!
       
  1638     Sends a request to the server set by setHost() or as specified in
       
  1639     the constructor. Uses the \a header as the HTTP request header.
       
  1640     You are responsible for setting up a header that is appropriate
       
  1641     for your request.
       
  1642 
       
  1643     The incoming data comes via the \a data IO device.
       
  1644 
       
  1645     If the IO device \a to is 0 the readyRead() signal is emitted
       
  1646     every time new content data is available to read.
       
  1647 
       
  1648     If the IO device \a to is not 0, the content data of the response
       
  1649     is written directly to the device. Make sure that the \a to
       
  1650     pointer is valid for the duration of the operation (it is safe to
       
  1651     delete it when the requestFinished() signal is emitted).
       
  1652 
       
  1653     The function does not block and returns immediately. The request
       
  1654     is scheduled, and its execution is performed asynchronously. The
       
  1655     function returns a unique identifier which is passed by
       
  1656     requestStarted() and requestFinished().
       
  1657 
       
  1658     When the request is started the requestStarted() signal is
       
  1659     emitted. When it is finished the requestFinished() signal is
       
  1660     emitted.
       
  1661 
       
  1662     \sa setHost() get() post() head() requestStarted() requestFinished() done()
       
  1663 */
       
  1664 int Q3Http::request( const Q3HttpRequestHeader &header, QIODevice *data, QIODevice *to )
       
  1665 {
       
  1666     return addRequest( new Q3HttpNormalRequest( header, data, to ) );
       
  1667 }
       
  1668 
       
  1669 /*!
       
  1670     \overload
       
  1671 
       
  1672     \a data is used as the content data of the HTTP request.
       
  1673 */
       
  1674 int Q3Http::request( const Q3HttpRequestHeader &header, const QByteArray &data, QIODevice *to  )
       
  1675 {
       
  1676     return addRequest( new Q3HttpNormalRequest( header, new QByteArray(data), to ) );
       
  1677 }
       
  1678 
       
  1679 /*!
       
  1680     Closes the connection; this is useful if you have a keep-alive
       
  1681     connection and want to close it.
       
  1682 
       
  1683     For the requests issued with get(), post() and head(), Q3Http sets
       
  1684     the connection to be keep-alive. You can also do this using the
       
  1685     header you pass to the request() function. Q3Http only closes the
       
  1686     connection to the HTTP server if the response header requires it
       
  1687     to do so.
       
  1688 
       
  1689     The function does not block and returns immediately. The request
       
  1690     is scheduled, and its execution is performed asynchronously. The
       
  1691     function returns a unique identifier which is passed by
       
  1692     requestStarted() and requestFinished().
       
  1693 
       
  1694     When the request is started the requestStarted() signal is
       
  1695     emitted. When it is finished the requestFinished() signal is
       
  1696     emitted.
       
  1697 
       
  1698     If you want to close the connection immediately, you have to use
       
  1699     abort() instead.
       
  1700 
       
  1701     \sa stateChanged() abort() requestStarted() requestFinished() done()
       
  1702 */
       
  1703 int Q3Http::closeConnection()
       
  1704 {
       
  1705     return addRequest( new Q3HttpCloseRequest() );
       
  1706 }
       
  1707 
       
  1708 int Q3Http::addRequest( Q3HttpRequest *req )
       
  1709 {
       
  1710     d->pending.append( req );
       
  1711 
       
  1712     if ( d->pending.count() == 1 )
       
  1713 	// don't emit the requestStarted() signal before the id is returned
       
  1714 	QTimer::singleShot( 0, this, SLOT(startNextRequest()) );
       
  1715 
       
  1716     return req->id;
       
  1717 }
       
  1718 
       
  1719 void Q3Http::startNextRequest()
       
  1720 {
       
  1721     Q3HttpRequest *r = d->pending.getFirst();
       
  1722     if ( r == 0 )
       
  1723 	return;
       
  1724 
       
  1725     d->error = NoError;
       
  1726     d->errorString = QHttp::tr( "Unknown error" );
       
  1727 
       
  1728     if ( bytesAvailable() )
       
  1729 	readAll(); // clear the data
       
  1730     emit requestStarted( r->id );
       
  1731     r->start( this );
       
  1732 }
       
  1733 
       
  1734 void Q3Http::sendRequest()
       
  1735 {
       
  1736     if ( d->hostname.isNull() ) {
       
  1737 	finishedWithError( QHttp::tr("No server set to connect to"), UnknownError );
       
  1738 	return;
       
  1739     }
       
  1740 
       
  1741     killIdleTimer();
       
  1742 
       
  1743     // Do we need to setup a new connection or can we reuse an
       
  1744     // existing one ?
       
  1745     if ( d->socket.peerName() != d->hostname || d->socket.peerPort() != d->port
       
  1746         || d->socket.state() != Q3Socket::Connection ) {
       
  1747 	setState( Q3Http::Connecting );
       
  1748 	d->socket.connectToHost( d->hostname, d->port );
       
  1749     } else {
       
  1750         slotConnected();
       
  1751     }
       
  1752 
       
  1753 }
       
  1754 
       
  1755 void Q3Http::finishedWithSuccess()
       
  1756 {
       
  1757     Q3HttpRequest *r = d->pending.getFirst();
       
  1758     if ( r == 0 )
       
  1759 	return;
       
  1760 
       
  1761     emit requestFinished( r->id, false );
       
  1762     d->pending.removeFirst();
       
  1763     if ( d->pending.isEmpty() ) {
       
  1764 	emit done( false );
       
  1765     } else {
       
  1766 	startNextRequest();
       
  1767     }
       
  1768 }
       
  1769 
       
  1770 void Q3Http::finishedWithError( const QString& detail, int errorCode )
       
  1771 {
       
  1772     Q3HttpRequest *r = d->pending.getFirst();
       
  1773     if ( r == 0 )
       
  1774 	return;
       
  1775 
       
  1776     d->error = (Error)errorCode;
       
  1777     d->errorString = detail;
       
  1778     emit requestFinished( r->id, true );
       
  1779 
       
  1780     d->pending.clear();
       
  1781     emit done( true );
       
  1782 }
       
  1783 
       
  1784 void Q3Http::slotClosed()
       
  1785 {
       
  1786     if ( d->state == Closing )
       
  1787 	return;
       
  1788 
       
  1789     if ( d->state == Reading ) {
       
  1790 	if ( d->response.hasKey( QLatin1String("content-length") ) ) {
       
  1791 	    // We got Content-Length, so did we get all bytes?
       
  1792 	    if ( d->bytesDone+bytesAvailable() != d->response.contentLength() ) {
       
  1793 		finishedWithError( QHttp::tr("Wrong content length"), WrongContentLength );
       
  1794 	    }
       
  1795 	}
       
  1796     } else if ( d->state == Connecting || d->state == Sending ) {
       
  1797 	finishedWithError( QHttp::tr("Server closed connection unexpectedly"), UnexpectedClose );
       
  1798     }
       
  1799 
       
  1800     d->postDevice = 0;
       
  1801     setState( Closing );
       
  1802     d->idleTimer = startTimer( 0 );
       
  1803 }
       
  1804 
       
  1805 void Q3Http::slotConnected()
       
  1806 {
       
  1807     if ( d->state != Sending ) {
       
  1808 	d->bytesDone = 0;
       
  1809 	setState( Sending );
       
  1810     }
       
  1811 
       
  1812     QString str = d->header.toString();
       
  1813     d->bytesTotal = str.length();
       
  1814     d->socket.writeBlock( str.latin1(), d->bytesTotal );
       
  1815 #if defined(Q3HTTP_DEBUG)
       
  1816     qDebug( "Q3Http: write request header:\n---{\n%s}---", str.latin1() );
       
  1817 #endif
       
  1818 
       
  1819     if ( d->postDevice ) {
       
  1820 	d->bytesTotal += d->postDevice->size();
       
  1821     } else {
       
  1822 	d->bytesTotal += d->buffer.size();
       
  1823 	d->socket.writeBlock( d->buffer.data(), d->buffer.size() );
       
  1824 	d->buffer = QByteArray(); // save memory
       
  1825     }
       
  1826 }
       
  1827 
       
  1828 void Q3Http::slotError( int err )
       
  1829 {
       
  1830     d->postDevice = 0;
       
  1831 
       
  1832     if ( d->state == Connecting || d->state == Reading || d->state == Sending ) {
       
  1833 	switch ( err ) {
       
  1834 	    case Q3Socket::ErrConnectionRefused:
       
  1835 		finishedWithError( QHttp::tr("Connection refused"), ConnectionRefused );
       
  1836 		break;
       
  1837 	    case Q3Socket::ErrHostNotFound:
       
  1838 		finishedWithError( QHttp::tr("Host %1 not found").arg(d->socket.peerName()), HostNotFound );
       
  1839 		break;
       
  1840 	    default:
       
  1841 		finishedWithError( QHttp::tr("HTTP request failed"), UnknownError );
       
  1842 		break;
       
  1843 	}
       
  1844     }
       
  1845 
       
  1846     close();
       
  1847 }
       
  1848 
       
  1849 void Q3Http::slotBytesWritten( int written )
       
  1850 {
       
  1851     d->bytesDone += written;
       
  1852     emit dataSendProgress( d->bytesDone, d->bytesTotal );
       
  1853 
       
  1854     if ( !d->postDevice )
       
  1855 	return;
       
  1856 
       
  1857     if ( d->socket.bytesToWrite() == 0 ) {
       
  1858 	int max = qMin<int>( 4096, d->postDevice->size() - d->postDevice->at() );
       
  1859 	QByteArray arr( max );
       
  1860 
       
  1861 	int n = d->postDevice->readBlock( arr.data(), max );
       
  1862 	if ( n != max ) {
       
  1863 	    qWarning("Could not read enough bytes from the device");
       
  1864 	    close();
       
  1865 	    return;
       
  1866 	}
       
  1867 	if ( d->postDevice->atEnd() ) {
       
  1868 	    d->postDevice = 0;
       
  1869 	}
       
  1870 
       
  1871 	d->socket.writeBlock( arr.data(), max );
       
  1872     }
       
  1873 }
       
  1874 
       
  1875 void Q3Http::slotReadyRead()
       
  1876 {
       
  1877     if ( d->state != Reading ) {
       
  1878 	setState( Reading );
       
  1879 	d->buffer = QByteArray();
       
  1880 	d->readHeader = true;
       
  1881 	d->headerStr = QLatin1String("");
       
  1882 	d->bytesDone = 0;
       
  1883 	d->chunkedSize = -1;
       
  1884     }
       
  1885 
       
  1886     while ( d->readHeader ) {
       
  1887 	bool end = false;
       
  1888 	QString tmp;
       
  1889 	while ( !end && d->socket.canReadLine() ) {
       
  1890 	    tmp = QLatin1String(d->socket.readLine());
       
  1891 	    if ( tmp == QLatin1String("\r\n") || tmp == QLatin1String("\n") )
       
  1892 		end = true;
       
  1893 	    else
       
  1894 		d->headerStr += tmp;
       
  1895 	}
       
  1896 
       
  1897 	if ( !end )
       
  1898 	    return;
       
  1899 
       
  1900 #if defined(Q3HTTP_DEBUG)
       
  1901 	qDebug( "Q3Http: read response header:\n---{\n%s}---", d->headerStr.latin1() );
       
  1902 #endif
       
  1903 	d->response = Q3HttpResponseHeader( d->headerStr );
       
  1904 	d->headerStr = QLatin1String("");
       
  1905 #if defined(Q3HTTP_DEBUG)
       
  1906 	qDebug( "Q3Http: read response header:\n---{\n%s}---", d->response.toString().latin1() );
       
  1907 #endif
       
  1908 	// Check header
       
  1909 	if ( !d->response.isValid() ) {
       
  1910 	    finishedWithError( QHttp::tr("Invalid HTTP response header"), InvalidResponseHeader );
       
  1911 	    close();
       
  1912 	    return;
       
  1913 	}
       
  1914 
       
  1915 	// The 100-continue header is ignored, because when using the
       
  1916 	// POST method, we send both the request header and data in
       
  1917 	// one chunk.
       
  1918 	if (d->response.statusCode() != 100) {
       
  1919 	    d->readHeader = false;
       
  1920 	    if ( d->response.hasKey( QLatin1String("transfer-encoding") ) &&
       
  1921 		 d->response.value( QLatin1String("transfer-encoding") ).lower().contains( QLatin1String("chunked") ) )
       
  1922 		d->chunkedSize = 0;
       
  1923 
       
  1924 	    emit responseHeaderReceived( d->response );
       
  1925 	}
       
  1926     }
       
  1927 
       
  1928     if ( !d->readHeader ) {
       
  1929 	bool everythingRead = false;
       
  1930 
       
  1931 	if ( currentRequest().method() == QLatin1String("HEAD") ) {
       
  1932 	    everythingRead = true;
       
  1933 	} else {
       
  1934 	    Q_ULONG n = d->socket.bytesAvailable();
       
  1935 	    QByteArray *arr = 0;
       
  1936 	    if ( d->chunkedSize != -1 ) {
       
  1937 		// transfer-encoding is chunked
       
  1938 		for ( ;; ) {
       
  1939 		    // get chunk size
       
  1940 		    if ( d->chunkedSize == 0 ) {
       
  1941 			if ( !d->socket.canReadLine() )
       
  1942 			    break;
       
  1943 			QString sizeString = QLatin1String(d->socket.readLine());
       
  1944 			int tPos = sizeString.find( QLatin1Char(';') );
       
  1945 			if ( tPos != -1 )
       
  1946 			    sizeString.truncate( tPos );
       
  1947 			bool ok;
       
  1948 			d->chunkedSize = sizeString.toInt( &ok, 16 );
       
  1949 			if ( !ok ) {
       
  1950 			    finishedWithError( QHttp::tr("Invalid HTTP chunked body"), WrongContentLength );
       
  1951 			    close();
       
  1952                             delete arr;
       
  1953 			    return;
       
  1954 			}
       
  1955 			if ( d->chunkedSize == 0 ) // last-chunk
       
  1956 			    d->chunkedSize = -2;
       
  1957 		    }
       
  1958 
       
  1959 		    // read trailer
       
  1960 		    while ( d->chunkedSize == -2 && d->socket.canReadLine() ) {
       
  1961 			QString read = QLatin1String(d->socket.readLine());
       
  1962 			if ( read == QLatin1String("\r\n") || read == QLatin1String("\n") )
       
  1963 			    d->chunkedSize = -1;
       
  1964 		    }
       
  1965 		    if ( d->chunkedSize == -1 ) {
       
  1966 			everythingRead = true;
       
  1967 			break;
       
  1968 		    }
       
  1969 
       
  1970 		    // make sure that you can read the terminating CRLF,
       
  1971 		    // otherwise wait until next time...
       
  1972 		    n = d->socket.bytesAvailable();
       
  1973 		    if ( n == 0 )
       
  1974 			break;
       
  1975 		    if ( (Q_LONG)n == d->chunkedSize || (Q_LONG)n == d->chunkedSize+1 ) {
       
  1976 			n = d->chunkedSize - 1;
       
  1977 			if ( n == 0 )
       
  1978 			    break;
       
  1979 		    }
       
  1980 
       
  1981 		    // read data
       
  1982 		    uint toRead = QMIN( (Q_LONG)n, (d->chunkedSize < 0 ? (Q_LONG)n : d->chunkedSize) );
       
  1983 		    if ( !arr )
       
  1984 			arr = new QByteArray( 0 );
       
  1985 		    uint oldArrSize = arr->size();
       
  1986 		    arr->resize( oldArrSize + toRead );
       
  1987 		    Q_LONG read = d->socket.readBlock( arr->data()+oldArrSize, toRead );
       
  1988 		    arr->resize( oldArrSize + read );
       
  1989 
       
  1990 		    d->chunkedSize -= read;
       
  1991 
       
  1992 		    if ( d->chunkedSize == 0 && n - read >= 2 ) {
       
  1993 			// read terminating CRLF
       
  1994 			char tmp[2];
       
  1995 			d->socket.readBlock( tmp, 2 );
       
  1996 			if ( tmp[0] != '\r' || tmp[1] != '\n' ) {
       
  1997 			    finishedWithError( QHttp::tr("Invalid HTTP chunked body"), WrongContentLength );
       
  1998 			    close();
       
  1999                             delete arr;
       
  2000 			    return;
       
  2001 			}
       
  2002 		    }
       
  2003 		}
       
  2004 	    } else if ( d->response.hasContentLength() ) {
       
  2005 		n = qMin<ulong>( d->response.contentLength() - d->bytesDone, n );
       
  2006 		if ( n > 0 ) {
       
  2007 		    arr = new QByteArray( n );
       
  2008 		    Q_LONG read = d->socket.readBlock( arr->data(), n );
       
  2009 		    arr->resize( read );
       
  2010 		}
       
  2011 		if ( d->bytesDone + bytesAvailable() + n == d->response.contentLength() )
       
  2012 		    everythingRead = true;
       
  2013 	    } else if ( n > 0 ) {
       
  2014 		// workaround for VC++ bug
       
  2015 		QByteArray temp = d->socket.readAll();
       
  2016 		arr = new QByteArray( temp );
       
  2017 	    }
       
  2018 
       
  2019 	    if ( arr ) {
       
  2020 		n = arr->size();
       
  2021 		if ( d->toDevice ) {
       
  2022 		    d->toDevice->writeBlock( arr->data(), n );
       
  2023 		    delete arr;
       
  2024 		    d->bytesDone += n;
       
  2025 #if defined(Q3HTTP_DEBUG)
       
  2026 		    qDebug( "Q3Http::slotReadyRead(): read %ld bytes (%d bytes done)", n, d->bytesDone );
       
  2027 #endif
       
  2028 		    if ( d->response.hasContentLength() )
       
  2029 			emit dataReadProgress( d->bytesDone, d->response.contentLength() );
       
  2030 		    else
       
  2031 			emit dataReadProgress( d->bytesDone, 0 );
       
  2032 		} else {
       
  2033 		    d->rba.append( arr );
       
  2034 #if defined(Q3HTTP_DEBUG)
       
  2035 		    qDebug( "Q3Http::slotReadyRead(): read %ld bytes (%ld bytes done)", n, d->bytesDone + bytesAvailable() );
       
  2036 #endif
       
  2037 		    if ( d->response.hasContentLength() )
       
  2038 			emit dataReadProgress( d->bytesDone + bytesAvailable(), d->response.contentLength() );
       
  2039 		    else
       
  2040 			emit dataReadProgress( d->bytesDone + bytesAvailable(), 0 );
       
  2041 		    emit readyRead( d->response );
       
  2042 		}
       
  2043 	    }
       
  2044 	}
       
  2045 
       
  2046 	if ( everythingRead ) {
       
  2047 	    // Handle "Connection: close"
       
  2048 	    if ( d->response.value(QLatin1String("connection")).lower() == QLatin1String("close") ) {
       
  2049 		close();
       
  2050 	    } else {
       
  2051 		setState( Connected );
       
  2052 		// Start a timer, so that we emit the keep alive signal
       
  2053 		// "after" this method returned.
       
  2054 		d->idleTimer = startTimer( 0 );
       
  2055 	    }
       
  2056 	}
       
  2057     }
       
  2058 }
       
  2059 
       
  2060 /*!
       
  2061     Returns the current state of the object. When the state changes,
       
  2062     the stateChanged() signal is emitted.
       
  2063 
       
  2064     \sa State stateChanged()
       
  2065 */
       
  2066 Q3Http::State Q3Http::state() const
       
  2067 {
       
  2068     return d->state;
       
  2069 }
       
  2070 
       
  2071 /*!
       
  2072     Returns the last error that occurred. This is useful to find out
       
  2073     what happened when receiving a requestFinished() or a done()
       
  2074     signal with the \c error argument \c true.
       
  2075 
       
  2076     If you start a new request, the error status is reset to \c NoError.
       
  2077 */
       
  2078 Q3Http::Error Q3Http::error() const
       
  2079 {
       
  2080     return d->error;
       
  2081 }
       
  2082 
       
  2083 /*!
       
  2084     Returns a human-readable description of the last error that
       
  2085     occurred. This is useful to present a error message to the user
       
  2086     when receiving a requestFinished() or a done() signal with the \c
       
  2087     error argument \c true.
       
  2088 */
       
  2089 QString Q3Http::errorString() const
       
  2090 {
       
  2091     return d->errorString;
       
  2092 }
       
  2093 
       
  2094 /*! \reimp
       
  2095 */
       
  2096 void Q3Http::timerEvent( QTimerEvent *e )
       
  2097 {
       
  2098     if ( e->timerId() == d->idleTimer ) {
       
  2099 	killTimer( d->idleTimer );
       
  2100 	d->idleTimer = 0;
       
  2101 
       
  2102 	if ( d->state == Connected ) {
       
  2103 	    finishedWithSuccess();
       
  2104 	} else if ( d->state != Unconnected ) {
       
  2105 	    setState( Unconnected );
       
  2106 	    finishedWithSuccess();
       
  2107 	}
       
  2108     } else {
       
  2109 	QObject::timerEvent( e );
       
  2110     }
       
  2111 }
       
  2112 
       
  2113 void Q3Http::killIdleTimer()
       
  2114 {
       
  2115     if (d->idleTimer)
       
  2116         killTimer( d->idleTimer );
       
  2117     d->idleTimer = 0;
       
  2118 }
       
  2119 
       
  2120 void Q3Http::setState( int s )
       
  2121 {
       
  2122 #if defined(Q3HTTP_DEBUG)
       
  2123     qDebug( "Q3Http state changed %d -> %d", d->state, s );
       
  2124 #endif
       
  2125     d->state = (State)s;
       
  2126     emit stateChanged( s );
       
  2127 }
       
  2128 
       
  2129 void Q3Http::close()
       
  2130 {
       
  2131     // If no connection is open -> ignore
       
  2132     if ( d->state == Closing || d->state == Unconnected )
       
  2133 	return;
       
  2134 
       
  2135     d->postDevice = 0;
       
  2136     setState( Closing );
       
  2137 
       
  2138     // Already closed ?
       
  2139     if ( !d->socket.isOpen() ) {
       
  2140 	d->idleTimer = startTimer( 0 );
       
  2141     } else {
       
  2142 	// Close now.
       
  2143 	d->socket.close();
       
  2144 
       
  2145 	// Did close succeed immediately ?
       
  2146 	if ( d->socket.state() == Q3Socket::Idle ) {
       
  2147 	    // Prepare to emit the requestFinished() signal.
       
  2148 	    d->idleTimer = startTimer( 0 );
       
  2149 	}
       
  2150     }
       
  2151 }
       
  2152 
       
  2153 /**********************************************************************
       
  2154  *
       
  2155  * Q3Http implementation of the Q3NetworkProtocol interface
       
  2156  *
       
  2157  *********************************************************************/
       
  2158 /*! \reimp
       
  2159 */
       
  2160 int Q3Http::supportedOperations() const
       
  2161 {
       
  2162     return OpGet | OpPut;
       
  2163 }
       
  2164 
       
  2165 /*! \reimp
       
  2166 */
       
  2167 void Q3Http::operationGet( Q3NetworkOperation *op )
       
  2168 {
       
  2169     connect( this, SIGNAL(readyRead(Q3HttpResponseHeader)),
       
  2170 	    this, SLOT(clientReply(Q3HttpResponseHeader)) );
       
  2171     connect( this, SIGNAL(done(bool)),
       
  2172 	    this, SLOT(clientDone(bool)) );
       
  2173     connect( this, SIGNAL(stateChanged(int)),
       
  2174 	    this, SLOT(clientStateChanged(int)) );
       
  2175 
       
  2176     bytesRead = 0;
       
  2177     op->setState( StInProgress );
       
  2178     Q3Url u( operationInProgress()->arg( 0 ) );
       
  2179     Q3HttpRequestHeader header( QLatin1String("GET"), u.encodedPathAndQuery(), 1, 0 );
       
  2180     header.setValue( QLatin1String("Host"), u.host() );
       
  2181     setHost( u.host(), u.port() != -1 ? u.port() : 80 );
       
  2182     request( header );
       
  2183 }
       
  2184 
       
  2185 /*! \reimp
       
  2186 */
       
  2187 void Q3Http::operationPut( Q3NetworkOperation *op )
       
  2188 {
       
  2189     connect( this, SIGNAL(readyRead(Q3HttpResponseHeader)),
       
  2190 	    this, SLOT(clientReply(Q3HttpResponseHeader)) );
       
  2191     connect( this, SIGNAL(done(bool)),
       
  2192 	    this, SLOT(clientDone(bool)) );
       
  2193     connect( this, SIGNAL(stateChanged(int)),
       
  2194 	    this, SLOT(clientStateChanged(int)) );
       
  2195 
       
  2196     bytesRead = 0;
       
  2197     op->setState( StInProgress );
       
  2198     Q3Url u( operationInProgress()->arg( 0 ) );
       
  2199     Q3HttpRequestHeader header( QLatin1String("POST"), u.encodedPathAndQuery(), 1, 0 );
       
  2200     header.setValue( QLatin1String("Host"), u.host() );
       
  2201     setHost( u.host(), u.port() != -1 ? u.port() : 80 );
       
  2202     request( header, op->rawArg(1) );
       
  2203 }
       
  2204 
       
  2205 void Q3Http::clientReply( const Q3HttpResponseHeader &rep )
       
  2206 {
       
  2207     Q3NetworkOperation *op = operationInProgress();
       
  2208     if ( op ) {
       
  2209 	if ( rep.statusCode() >= 400 && rep.statusCode() < 600 ) {
       
  2210 	    op->setState( StFailed );
       
  2211 	    op->setProtocolDetail(
       
  2212             QString::fromLatin1("%1 %2").arg(rep.statusCode()).arg(rep.reasonPhrase())
       
  2213 						    );
       
  2214 	    switch ( rep.statusCode() ) {
       
  2215 		case 401:
       
  2216 		case 403:
       
  2217 		case 405:
       
  2218 		    op->setErrorCode( ErrPermissionDenied );
       
  2219 		    break;
       
  2220 		case 404:
       
  2221 		    op->setErrorCode(ErrFileNotExisting );
       
  2222 		    break;
       
  2223 		default:
       
  2224 		    if ( op->operation() == OpGet )
       
  2225 			op->setErrorCode( ErrGet );
       
  2226 		    else
       
  2227 			op->setErrorCode( ErrPut );
       
  2228 		    break;
       
  2229 	    }
       
  2230 	}
       
  2231 	// ### In cases of an error, should we still emit the data() signals?
       
  2232 	if ( op->operation() == OpGet && bytesAvailable() > 0 ) {
       
  2233 	    QByteArray ba = readAll();
       
  2234 	    emit data( ba, op );
       
  2235 	    bytesRead += ba.size();
       
  2236 	    if ( rep.hasContentLength() ) {
       
  2237 		emit dataTransferProgress( bytesRead, rep.contentLength(), op );
       
  2238 	    }
       
  2239 	}
       
  2240     }
       
  2241 }
       
  2242 
       
  2243 void Q3Http::clientDone( bool err )
       
  2244 {
       
  2245     disconnect( this, SIGNAL(readyRead(Q3HttpResponseHeader)),
       
  2246 	    this, SLOT(clientReply(Q3HttpResponseHeader)) );
       
  2247     disconnect( this, SIGNAL(done(bool)),
       
  2248 	    this, SLOT(clientDone(bool)) );
       
  2249     disconnect( this, SIGNAL(stateChanged(int)),
       
  2250 	    this, SLOT(clientStateChanged(int)) );
       
  2251 
       
  2252     if ( err ) {
       
  2253 	Q3NetworkOperation *op = operationInProgress();
       
  2254 	if ( op ) {
       
  2255 	    op->setState( Q3NetworkProtocol::StFailed );
       
  2256 	    op->setProtocolDetail( errorString() );
       
  2257 	    switch ( error() ) {
       
  2258 		case ConnectionRefused:
       
  2259 		    op->setErrorCode( ErrHostNotFound );
       
  2260 		    break;
       
  2261 		case HostNotFound:
       
  2262 		    op->setErrorCode( ErrHostNotFound );
       
  2263 		    break;
       
  2264 		default:
       
  2265 		    if ( op->operation() == OpGet )
       
  2266 			op->setErrorCode( ErrGet );
       
  2267 		    else
       
  2268 			op->setErrorCode( ErrPut );
       
  2269 		    break;
       
  2270 	    }
       
  2271 	    emit finished( op );
       
  2272 	}
       
  2273     } else {
       
  2274 	Q3NetworkOperation *op = operationInProgress();
       
  2275 	if ( op ) {
       
  2276 	    if ( op->state() != StFailed ) {
       
  2277 		op->setState( Q3NetworkProtocol::StDone );
       
  2278 		op->setErrorCode( Q3NetworkProtocol::NoError );
       
  2279 	    }
       
  2280 	    emit finished( op );
       
  2281 	}
       
  2282     }
       
  2283 
       
  2284 }
       
  2285 
       
  2286 void Q3Http::clientStateChanged( int state )
       
  2287 {
       
  2288     if ( url() ) {
       
  2289 	switch ( (State)state ) {
       
  2290 	    case Connecting:
       
  2291 		emit connectionStateChanged( ConHostFound, QHttp::tr( "Host %1 found" ).arg( url()->host() ) );
       
  2292 		break;
       
  2293 	    case Sending:
       
  2294 		emit connectionStateChanged( ConConnected, QHttp::tr( "Connected to host %1" ).arg( url()->host() ) );
       
  2295 		break;
       
  2296 	    case Unconnected:
       
  2297 		emit connectionStateChanged( ConClosed, QHttp::tr( "Connection to %1 closed" ).arg( url()->host() ) );
       
  2298 		break;
       
  2299 	    default:
       
  2300 		break;
       
  2301 	}
       
  2302     } else {
       
  2303 	switch ( (State)state ) {
       
  2304 	    case Connecting:
       
  2305 		emit connectionStateChanged( ConHostFound, QHttp::tr( "Host found" ) );
       
  2306 		break;
       
  2307 	    case Sending:
       
  2308 		emit connectionStateChanged( ConConnected, QHttp::tr( "Connected to host" ) );
       
  2309 		break;
       
  2310 	    case Unconnected:
       
  2311 		emit connectionStateChanged( ConClosed, QHttp::tr( "Connection closed" ) );
       
  2312 		break;
       
  2313 	    default:
       
  2314 		break;
       
  2315 	}
       
  2316     }
       
  2317 }
       
  2318 
       
  2319 QT_END_NAMESPACE
       
  2320 
       
  2321 #endif