00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include <qplatformdefs.h>
00025 #include "q3http.h"
00026
00027 #ifndef QT_NO_NETWORKPROTOCOL_HTTP
00028
00029 #include "q3socket.h"
00030 #include "qtextstream.h"
00031 #include "qmap.h"
00032 #include "qstring.h"
00033 #include "qstringlist.h"
00034 #include "q3cstring.h"
00035 #include "qbuffer.h"
00036 #include "q3urloperator.h"
00037 #include "qtimer.h"
00038 #include "private/q3membuf_p.h"
00039 #include "qevent.h"
00040 #include "q3url.h"
00041 #include "qhttp.h"
00042
00043
00044
00045 class Q3HttpPrivate
00046 {
00047 public:
00048 Q3HttpPrivate() :
00049 state( Q3Http::Unconnected ),
00050 error( Q3Http::NoError ),
00051 hostname( QString() ),
00052 port( 0 ),
00053 toDevice( 0 ),
00054 postDevice( 0 ),
00055 bytesDone( 0 ),
00056 chunkedSize( -1 ),
00057 idleTimer( 0 )
00058 {
00059 pending.setAutoDelete( true );
00060 }
00061
00062 Q3Socket socket;
00063 Q3PtrList<Q3HttpRequest> pending;
00064
00065 Q3Http::State state;
00066 Q3Http::Error error;
00067 QString errorString;
00068
00069 QString hostname;
00070 Q_UINT16 port;
00071
00072 QByteArray buffer;
00073 QIODevice* toDevice;
00074 QIODevice* postDevice;
00075
00076 uint bytesDone;
00077 uint bytesTotal;
00078 Q_LONG chunkedSize;
00079
00080 Q3HttpRequestHeader header;
00081
00082 bool readHeader;
00083 QString headerStr;
00084 Q3HttpResponseHeader response;
00085
00086 int idleTimer;
00087
00088 Q3Membuf rba;
00089 };
00090
00091 class Q3HttpRequest
00092 {
00093 public:
00094 Q3HttpRequest()
00095 {
00096 id = ++idCounter;
00097 }
00098 virtual ~Q3HttpRequest()
00099 { }
00100
00101 virtual void start( Q3Http * ) = 0;
00102 virtual bool hasRequestHeader();
00103 virtual Q3HttpRequestHeader requestHeader();
00104
00105 virtual QIODevice* sourceDevice() = 0;
00106 virtual QIODevice* destinationDevice() = 0;
00107
00108 int id;
00109
00110 private:
00111 static int idCounter;
00112 };
00113
00114 int Q3HttpRequest::idCounter = 0;
00115
00116 bool Q3HttpRequest::hasRequestHeader()
00117 {
00118 return false;
00119 }
00120
00121 Q3HttpRequestHeader Q3HttpRequest::requestHeader()
00122 {
00123 return Q3HttpRequestHeader();
00124 }
00125
00126
00127
00128
00129
00130
00131
00132 class Q3HttpNormalRequest : public Q3HttpRequest
00133 {
00134 public:
00135 Q3HttpNormalRequest( const Q3HttpRequestHeader &h, QIODevice *d, QIODevice *t ) :
00136 header(h), to(t)
00137 {
00138 is_ba = false;
00139 data.dev = d;
00140 }
00141
00142 Q3HttpNormalRequest( const Q3HttpRequestHeader &h, QByteArray *d, QIODevice *t ) :
00143 header(h), to(t)
00144 {
00145 is_ba = true;
00146 data.ba = d;
00147 }
00148
00149 ~Q3HttpNormalRequest()
00150 {
00151 if ( is_ba )
00152 delete data.ba;
00153 }
00154
00155 void start( Q3Http * );
00156 bool hasRequestHeader();
00157 Q3HttpRequestHeader requestHeader();
00158
00159 QIODevice* sourceDevice();
00160 QIODevice* destinationDevice();
00161
00162 protected:
00163 Q3HttpRequestHeader header;
00164
00165 private:
00166 union {
00167 QByteArray *ba;
00168 QIODevice *dev;
00169 } data;
00170 bool is_ba;
00171 QIODevice *to;
00172 };
00173
00174 void Q3HttpNormalRequest::start( Q3Http *http )
00175 {
00176 http->d->header = header;
00177
00178 if ( is_ba ) {
00179 http->d->buffer = *data.ba;
00180 if ( http->d->buffer.size() > 0 )
00181 http->d->header.setContentLength( http->d->buffer.size() );
00182
00183 http->d->postDevice = 0;
00184 } else {
00185 http->d->buffer = QByteArray();
00186
00187 if ( data.dev && ( data.dev->isOpen() || data.dev->open(IO_ReadOnly) ) ) {
00188 http->d->postDevice = data.dev;
00189 if ( http->d->postDevice->size() > 0 )
00190 http->d->header.setContentLength( http->d->postDevice->size() );
00191 } else {
00192 http->d->postDevice = 0;
00193 }
00194 }
00195
00196 if ( to && ( to->isOpen() || to->open(IO_WriteOnly) ) )
00197 http->d->toDevice = to;
00198 else
00199 http->d->toDevice = 0;
00200
00201 http->sendRequest();
00202 }
00203
00204 bool Q3HttpNormalRequest::hasRequestHeader()
00205 {
00206 return true;
00207 }
00208
00209 Q3HttpRequestHeader Q3HttpNormalRequest::requestHeader()
00210 {
00211 return header;
00212 }
00213
00214 QIODevice* Q3HttpNormalRequest::sourceDevice()
00215 {
00216 if ( is_ba )
00217 return 0;
00218 return data.dev;
00219 }
00220
00221 QIODevice* Q3HttpNormalRequest::destinationDevice()
00222 {
00223 return to;
00224 }
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236 class Q3HttpPGHRequest : public Q3HttpNormalRequest
00237 {
00238 public:
00239 Q3HttpPGHRequest( const Q3HttpRequestHeader &h, QIODevice *d, QIODevice *t ) :
00240 Q3HttpNormalRequest( h, d, t )
00241 { }
00242
00243 Q3HttpPGHRequest( const Q3HttpRequestHeader &h, QByteArray *d, QIODevice *t ) :
00244 Q3HttpNormalRequest( h, d, t )
00245 { }
00246
00247 ~Q3HttpPGHRequest()
00248 { }
00249
00250 void start( Q3Http * );
00251 };
00252
00253 void Q3HttpPGHRequest::start( Q3Http *http )
00254 {
00255 header.setValue( "Host", http->d->hostname );
00256 Q3HttpNormalRequest::start( http );
00257 }
00258
00259
00260
00261
00262
00263
00264
00265 class Q3HttpSetHostRequest : public Q3HttpRequest
00266 {
00267 public:
00268 Q3HttpSetHostRequest( const QString &h, Q_UINT16 p ) :
00269 hostname(h), port(p)
00270 { }
00271
00272 void start( Q3Http * );
00273
00274 QIODevice* sourceDevice()
00275 { return 0; }
00276 QIODevice* destinationDevice()
00277 { return 0; }
00278
00279 private:
00280 QString hostname;
00281 Q_UINT16 port;
00282 };
00283
00284 void Q3HttpSetHostRequest::start( Q3Http *http )
00285 {
00286 http->d->hostname = hostname;
00287 http->d->port = port;
00288 http->finishedWithSuccess();
00289 }
00290
00291
00292
00293
00294
00295
00296
00297 class Q3HttpCloseRequest : public Q3HttpRequest
00298 {
00299 public:
00300 Q3HttpCloseRequest()
00301 { }
00302 void start( Q3Http * );
00303
00304 QIODevice* sourceDevice()
00305 { return 0; }
00306 QIODevice* destinationDevice()
00307 { return 0; }
00308 };
00309
00310 void Q3HttpCloseRequest::start( Q3Http *http )
00311 {
00312 http->close();
00313 }
00314
00315
00316
00317
00318
00319
00320
00374 Q3HttpHeader::Q3HttpHeader()
00375 : valid( true )
00376 {
00377 }
00378
00382 Q3HttpHeader::Q3HttpHeader( const Q3HttpHeader& header )
00383 : valid( header.valid )
00384 {
00385 values = header.values;
00386 }
00387
00396 Q3HttpHeader::Q3HttpHeader( const QString& str )
00397 : valid( true )
00398 {
00399 parse( str );
00400 }
00401
00405 Q3HttpHeader::~Q3HttpHeader()
00406 {
00407 }
00408
00412 Q3HttpHeader& Q3HttpHeader::operator=( const Q3HttpHeader& h )
00413 {
00414 values = h.values;
00415 valid = h.valid;
00416 return *this;
00417 }
00418
00424 bool Q3HttpHeader::isValid() const
00425 {
00426 return valid;
00427 }
00428
00438 bool Q3HttpHeader::parse( const QString& str )
00439 {
00440 QStringList lst;
00441 int pos = str.find( '\n' );
00442 if ( pos > 0 && str.at( pos - 1 ) == '\r' )
00443 lst = QStringList::split( "\r\n", str.stripWhiteSpace(), false );
00444 else
00445 lst = QStringList::split( "\n", str.stripWhiteSpace(), false );
00446
00447 if ( lst.isEmpty() )
00448 return true;
00449
00450 QStringList lines;
00451 QStringList::Iterator it = lst.begin();
00452 for( ; it != lst.end(); ++it ) {
00453 if ( !(*it).isEmpty() ) {
00454 if ( (*it)[0].isSpace() ) {
00455 if ( !lines.isEmpty() ) {
00456 lines.last() += " ";
00457 lines.last() += (*it).stripWhiteSpace();
00458 }
00459 } else {
00460 lines.append( (*it) );
00461 }
00462 }
00463 }
00464
00465 int number = 0;
00466 it = lines.begin();
00467 for( ; it != lines.end(); ++it ) {
00468 if ( !parseLine( *it, number++ ) ) {
00469 valid = false;
00470 return false;
00471 }
00472 }
00473 return true;
00474 }
00475
00478 void Q3HttpHeader::setValid( bool v )
00479 {
00480 valid = v;
00481 }
00482
00489 QString Q3HttpHeader::value( const QString& key ) const
00490 {
00491 return values[ key.lower() ];
00492 }
00493
00499 QStringList Q3HttpHeader::keys() const
00500 {
00501 return values.keys();
00502 }
00503
00510 bool Q3HttpHeader::hasKey( const QString& key ) const
00511 {
00512 return values.contains( key.lower() );
00513 }
00514
00525 void Q3HttpHeader::setValue( const QString& key, const QString& value )
00526 {
00527 values[ key.lower() ] = value;
00528 }
00529
00535 void Q3HttpHeader::removeValue( const QString& key )
00536 {
00537 values.remove( key.lower() );
00538 }
00539
00548 bool Q3HttpHeader::parseLine( const QString& line, int )
00549 {
00550 int i = line.find( ":" );
00551 if ( i == -1 )
00552 return false;
00553
00554 values.insert( line.left( i ).stripWhiteSpace().lower(), line.mid( i + 1 ).stripWhiteSpace() );
00555
00556 return true;
00557 }
00558
00566 QString Q3HttpHeader::toString() const
00567 {
00568 if ( !isValid() )
00569 return "";
00570
00571 QString ret = "";
00572
00573 QMap<QString,QString>::ConstIterator it = values.begin();
00574 for( ; it != values.end(); ++it )
00575 ret += it.key() + ": " + it.data() + "\r\n";
00576
00577 return ret;
00578 }
00579
00586 bool Q3HttpHeader::hasContentLength() const
00587 {
00588 return hasKey( "content-length" );
00589 }
00590
00597 uint Q3HttpHeader::contentLength() const
00598 {
00599 return values[ "content-length" ].toUInt();
00600 }
00601
00608 void Q3HttpHeader::setContentLength( int len )
00609 {
00610 values[ "content-length" ] = QString::number( len );
00611 }
00612
00619 bool Q3HttpHeader::hasContentType() const
00620 {
00621 return hasKey( "content-type" );
00622 }
00623
00629 QString Q3HttpHeader::contentType() const
00630 {
00631 QString type = values[ "content-type" ];
00632 if ( type.isEmpty() )
00633 return QString();
00634
00635 int pos = type.find( ";" );
00636 if ( pos == -1 )
00637 return type;
00638
00639 return type.left( pos ).stripWhiteSpace();
00640 }
00641
00648 void Q3HttpHeader::setContentType( const QString& type )
00649 {
00650 values[ "content-type" ] = type;
00651 }
00652
00653
00654
00655
00656
00657
00658
00681 Q3HttpResponseHeader::Q3HttpResponseHeader()
00682 {
00683 setValid( false );
00684 }
00685
00691 Q3HttpResponseHeader::Q3HttpResponseHeader( int code, const QString& text, int majorVer, int minorVer )
00692 : Q3HttpHeader(), statCode( code ), reasonPhr( text ), majVer( majorVer ), minVer( minorVer )
00693 {
00694 }
00695
00699 Q3HttpResponseHeader::Q3HttpResponseHeader( const Q3HttpResponseHeader& header )
00700 : Q3HttpHeader( header ), statCode( header.statCode ), reasonPhr( header.reasonPhr ), majVer( header.majVer ), minVer( header.minVer )
00701 {
00702 }
00703
00712 Q3HttpResponseHeader::Q3HttpResponseHeader( const QString& str )
00713 : Q3HttpHeader()
00714 {
00715 parse( str );
00716 }
00717
00724 void Q3HttpResponseHeader::setStatusLine( int code, const QString& text, int majorVer, int minorVer )
00725 {
00726 setValid( true );
00727 statCode = code;
00728 reasonPhr = text;
00729 majVer = majorVer;
00730 minVer = minorVer;
00731 }
00732
00738 int Q3HttpResponseHeader::statusCode() const
00739 {
00740 return statCode;
00741 }
00742
00748 QString Q3HttpResponseHeader::reasonPhrase() const
00749 {
00750 return reasonPhr;
00751 }
00752
00758 int Q3HttpResponseHeader::majorVersion() const
00759 {
00760 return majVer;
00761 }
00762
00768 int Q3HttpResponseHeader::minorVersion() const
00769 {
00770 return minVer;
00771 }
00772
00775 bool Q3HttpResponseHeader::parseLine( const QString& line, int number )
00776 {
00777 if ( number != 0 )
00778 return Q3HttpHeader::parseLine( line, number );
00779
00780 QString l = line.simplifyWhiteSpace();
00781 if ( l.length() < 10 )
00782 return false;
00783
00784 if ( l.left( 5 ) == "HTTP/" && l[5].isDigit() && l[6] == '.' &&
00785 l[7].isDigit() && l[8] == ' ' && l[9].isDigit() ) {
00786 majVer = l[5].latin1() - '0';
00787 minVer = l[7].latin1() - '0';
00788
00789 int pos = l.find( ' ', 9 );
00790 if ( pos != -1 ) {
00791 reasonPhr = l.mid( pos + 1 );
00792 statCode = l.mid( 9, pos - 9 ).toInt();
00793 } else {
00794 statCode = l.mid( 9 ).toInt();
00795 reasonPhr.clear();
00796 }
00797 } else {
00798 return false;
00799 }
00800
00801 return true;
00802 }
00803
00806 QString Q3HttpResponseHeader::toString() const
00807 {
00808 QString ret( "HTTP/%1.%2 %3 %4\r\n%5\r\n" );
00809 return ret.arg( majVer ).arg ( minVer ).arg( statCode ).arg( reasonPhr ).arg( Q3HttpHeader::toString() );
00810 }
00811
00812
00813
00814
00815
00816
00817
00848 Q3HttpRequestHeader::Q3HttpRequestHeader()
00849 : Q3HttpHeader()
00850 {
00851 setValid( false );
00852 }
00853
00858 Q3HttpRequestHeader::Q3HttpRequestHeader( const QString& method, const QString& path, int majorVer, int minorVer )
00859 : Q3HttpHeader(), m( method ), p( path ), majVer( majorVer ), minVer( minorVer )
00860 {
00861 }
00862
00866 Q3HttpRequestHeader::Q3HttpRequestHeader( const Q3HttpRequestHeader& header )
00867 : Q3HttpHeader( header ), m( header.m ), p( header.p ), majVer( header.majVer ), minVer( header.minVer )
00868 {
00869 }
00870
00878 Q3HttpRequestHeader::Q3HttpRequestHeader( const QString& str )
00879 : Q3HttpHeader()
00880 {
00881 parse( str );
00882 }
00883
00891 void Q3HttpRequestHeader::setRequest( const QString& method, const QString& path, int majorVer, int minorVer )
00892 {
00893 setValid( true );
00894 m = method;
00895 p = path;
00896 majVer = majorVer;
00897 minVer = minorVer;
00898 }
00899
00905 QString Q3HttpRequestHeader::method() const
00906 {
00907 return m;
00908 }
00909
00915 QString Q3HttpRequestHeader::path() const
00916 {
00917 return p;
00918 }
00919
00925 int Q3HttpRequestHeader::majorVersion() const
00926 {
00927 return majVer;
00928 }
00929
00935 int Q3HttpRequestHeader::minorVersion() const
00936 {
00937 return minVer;
00938 }
00939
00942 bool Q3HttpRequestHeader::parseLine( const QString& line, int number )
00943 {
00944 if ( number != 0 )
00945 return Q3HttpHeader::parseLine( line, number );
00946
00947 QStringList lst = QStringList::split( " ", line.simplifyWhiteSpace() );
00948 if ( lst.count() > 0 ) {
00949 m = lst[0];
00950 if ( lst.count() > 1 ) {
00951 p = lst[1];
00952 if ( lst.count() > 2 ) {
00953 QString v = lst[2];
00954 if ( v.length() >= 8 && v.left( 5 ) == "HTTP/" &&
00955 v[5].isDigit() && v[6] == '.' && v[7].isDigit() ) {
00956 majVer = v[5].latin1() - '0';
00957 minVer = v[7].latin1() - '0';
00958 return true;
00959 }
00960 }
00961 }
00962 }
00963
00964 return false;
00965 }
00966
00969 QString Q3HttpRequestHeader::toString() const
00970 {
00971 QString first( "%1 %2");
00972 QString last(" HTTP/%3.%4\r\n%5\r\n" );
00973 return first.arg( m ).arg( p ) +
00974 last.arg( majVer ).arg( minVer ).arg( Q3HttpHeader::toString());
00975 }
00976
00977
00978
00979
00980
00981
00982
01152 Q3Http::Q3Http()
01153 {
01154 init();
01155 }
01156
01161 Q3Http::Q3Http( QObject* parent, const char* name )
01162 {
01163 if ( parent )
01164 parent->insertChild( this );
01165 setName( name );
01166 init();
01167 }
01168
01177 Q3Http::Q3Http( const QString &hostname, Q_UINT16 port, QObject* parent, const char* name )
01178 {
01179 if ( parent )
01180 parent->insertChild( this );
01181 setName( name );
01182 init();
01183
01184 d->hostname = hostname;
01185 d->port = port;
01186 }
01187
01188 void Q3Http::init()
01189 {
01190 bytesRead = 0;
01191 d = new Q3HttpPrivate;
01192 d->errorString = QHttp::tr( "Unknown error" );
01193
01194 connect( &d->socket, SIGNAL(connected()),
01195 this, SLOT(slotConnected()) );
01196 connect( &d->socket, SIGNAL(connectionClosed()),
01197 this, SLOT(slotClosed()) );
01198 connect( &d->socket, SIGNAL(delayedCloseFinished()),
01199 this, SLOT(slotClosed()) );
01200 connect( &d->socket, SIGNAL(readyRead()),
01201 this, SLOT(slotReadyRead()) );
01202 connect( &d->socket, SIGNAL(error(int)),
01203 this, SLOT(slotError(int)) );
01204 connect( &d->socket, SIGNAL(bytesWritten(int)),
01205 this, SLOT(slotBytesWritten(int)) );
01206
01207 d->idleTimer = startTimer( 0 );
01208 }
01209
01214 Q3Http::~Q3Http()
01215 {
01216 abort();
01217 delete d;
01218 }
01219
01383 void Q3Http::abort()
01384 {
01385 Q3HttpRequest *r = d->pending.getFirst();
01386 if ( r == 0 )
01387 return;
01388
01389 finishedWithError( QHttp::tr("Request aborted"), Aborted );
01390 clearPendingRequests();
01391 d->socket.clearPendingData();
01392 close();
01393 }
01394
01401 Q_ULONG Q3Http::bytesAvailable() const
01402 {
01403 #if defined(Q3HTTP_DEBUG)
01404 qDebug( "Q3Http::bytesAvailable(): %d bytes", (int)d->rba.size() );
01405 #endif
01406 return d->rba.size();
01407 }
01408
01415 Q_LONG Q3Http::readBlock( char *data, Q_ULONG maxlen )
01416 {
01417 if ( data == 0 && maxlen != 0 ) {
01418 #if defined(QT_CHECK_NULL)
01419 qWarning( "Q3Http::readBlock: Null pointer error" );
01420 #endif
01421 return -1;
01422 }
01423 if ( maxlen >= (Q_ULONG)d->rba.size() )
01424 maxlen = d->rba.size();
01425 d->rba.consumeBytes( maxlen, data );
01426
01427 d->bytesDone += maxlen;
01428 #if defined(Q3HTTP_DEBUG)
01429 qDebug( "Q3Http::readBlock(): read %d bytes (%d bytes done)", (int)maxlen, d->bytesDone );
01430 #endif
01431 return maxlen;
01432 }
01433
01439 QByteArray Q3Http::readAll()
01440 {
01441 Q_ULONG avail = bytesAvailable();
01442 QByteArray tmp( avail );
01443 Q_LONG read = readBlock( tmp.data(), avail );
01444 tmp.resize( read );
01445 return tmp;
01446 }
01447
01454 int Q3Http::currentId() const
01455 {
01456 Q3HttpRequest *r = d->pending.getFirst();
01457 if ( r == 0 )
01458 return 0;
01459 return r->id;
01460 }
01461
01470 Q3HttpRequestHeader Q3Http::currentRequest() const
01471 {
01472 Q3HttpRequest *r = d->pending.getFirst();
01473 if ( r != 0 && r->hasRequestHeader() )
01474 return r->requestHeader();
01475 return Q3HttpRequestHeader();
01476 }
01477
01488 QIODevice* Q3Http::currentSourceDevice() const
01489 {
01490 Q3HttpRequest *r = d->pending.getFirst();
01491 if ( !r )
01492 return 0;
01493 return r->sourceDevice();
01494 }
01495
01506 QIODevice* Q3Http::currentDestinationDevice() const
01507 {
01508 Q3HttpRequest *r = d->pending.getFirst();
01509 if ( !r )
01510 return 0;
01511 return r->destinationDevice();
01512 }
01513
01523 bool Q3Http::hasPendingRequests() const
01524 {
01525 return d->pending.count() > 1;
01526 }
01527
01535 void Q3Http::clearPendingRequests()
01536 {
01537 Q3HttpRequest *r = 0;
01538 if ( d->pending.count() > 0 )
01539 r = d->pending.take( 0 );
01540 d->pending.clear();
01541 if ( r )
01542 d->pending.append( r );
01543 }
01544
01560 int Q3Http::setHost(const QString &hostname, Q_UINT16 port )
01561 {
01562 return addRequest( new Q3HttpSetHostRequest( hostname, port ) );
01563 }
01564
01591 int Q3Http::get( const QString& path, QIODevice* to )
01592 {
01593 Q3HttpRequestHeader header( "GET", path );
01594 header.setValue( "Connection", "Keep-Alive" );
01595 return addRequest( new Q3HttpPGHRequest( header, (QIODevice*)0, to ) );
01596 }
01597
01626 int Q3Http::post( const QString& path, QIODevice* data, QIODevice* to )
01627 {
01628 Q3HttpRequestHeader header( "POST", path );
01629 header.setValue( "Connection", "Keep-Alive" );
01630 return addRequest( new Q3HttpPGHRequest( header, data, to ) );
01631 }
01632
01638 int Q3Http::post( const QString& path, const QByteArray& data, QIODevice* to )
01639 {
01640 Q3HttpRequestHeader header( "POST", path );
01641 header.setValue( "Connection", "Keep-Alive" );
01642 return addRequest( new Q3HttpPGHRequest( header, new QByteArray(data), to ) );
01643 }
01644
01663 int Q3Http::head( const QString& path )
01664 {
01665 Q3HttpRequestHeader header( "HEAD", path );
01666 header.setValue( "Connection", "Keep-Alive" );
01667 return addRequest( new Q3HttpPGHRequest( header, (QIODevice*)0, 0 ) );
01668 }
01669
01697 int Q3Http::request( const Q3HttpRequestHeader &header, QIODevice *data, QIODevice *to )
01698 {
01699 return addRequest( new Q3HttpNormalRequest( header, data, to ) );
01700 }
01701
01707 int Q3Http::request( const Q3HttpRequestHeader &header, const QByteArray &data, QIODevice *to )
01708 {
01709 return addRequest( new Q3HttpNormalRequest( header, new QByteArray(data), to ) );
01710 }
01711
01736 int Q3Http::closeConnection()
01737 {
01738 return addRequest( new Q3HttpCloseRequest() );
01739 }
01740
01741 int Q3Http::addRequest( Q3HttpRequest *req )
01742 {
01743 d->pending.append( req );
01744
01745 if ( d->pending.count() == 1 )
01746
01747 QTimer::singleShot( 0, this, SLOT(startNextRequest()) );
01748
01749 return req->id;
01750 }
01751
01752 void Q3Http::startNextRequest()
01753 {
01754 Q3HttpRequest *r = d->pending.getFirst();
01755 if ( r == 0 )
01756 return;
01757
01758 d->error = NoError;
01759 d->errorString = QHttp::tr( "Unknown error" );
01760
01761 if ( bytesAvailable() )
01762 readAll();
01763 emit requestStarted( r->id );
01764 r->start( this );
01765 }
01766
01767 void Q3Http::sendRequest()
01768 {
01769 if ( d->hostname.isNull() ) {
01770 finishedWithError( QHttp::tr("No server set to connect to"), UnknownError );
01771 return;
01772 }
01773
01774 killIdleTimer();
01775
01776
01777
01778 if ( d->socket.peerName() != d->hostname || d->socket.peerPort() != d->port
01779 || d->socket.state() != Q3Socket::Connection ) {
01780 setState( Q3Http::Connecting );
01781 d->socket.connectToHost( d->hostname, d->port );
01782 } else {
01783 slotConnected();
01784 }
01785
01786 }
01787
01788 void Q3Http::finishedWithSuccess()
01789 {
01790 Q3HttpRequest *r = d->pending.getFirst();
01791 if ( r == 0 )
01792 return;
01793
01794 emit requestFinished( r->id, false );
01795 d->pending.removeFirst();
01796 if ( d->pending.isEmpty() ) {
01797 emit done( false );
01798 } else {
01799 startNextRequest();
01800 }
01801 }
01802
01803 void Q3Http::finishedWithError( const QString& detail, int errorCode )
01804 {
01805 Q3HttpRequest *r = d->pending.getFirst();
01806 if ( r == 0 )
01807 return;
01808
01809 d->error = (Error)errorCode;
01810 d->errorString = detail;
01811 emit requestFinished( r->id, true );
01812
01813 d->pending.clear();
01814 emit done( true );
01815 }
01816
01817 void Q3Http::slotClosed()
01818 {
01819 if ( d->state == Closing )
01820 return;
01821
01822 if ( d->state == Reading ) {
01823 if ( d->response.hasKey( "content-length" ) ) {
01824
01825 if ( d->bytesDone+bytesAvailable() != d->response.contentLength() ) {
01826 finishedWithError( QHttp::tr("Wrong content length"), WrongContentLength );
01827 }
01828 }
01829 } else if ( d->state == Connecting || d->state == Sending ) {
01830 finishedWithError( QHttp::tr("Server closed connection unexpectedly"), UnexpectedClose );
01831 }
01832
01833 d->postDevice = 0;
01834 setState( Closing );
01835 d->idleTimer = startTimer( 0 );
01836 }
01837
01838 void Q3Http::slotConnected()
01839 {
01840 if ( d->state != Sending ) {
01841 d->bytesDone = 0;
01842 setState( Sending );
01843 }
01844
01845 QString str = d->header.toString();
01846 d->bytesTotal = str.length();
01847 d->socket.writeBlock( str.latin1(), d->bytesTotal );
01848 #if defined(Q3HTTP_DEBUG)
01849 qDebug( "Q3Http: write request header:\n---{\n%s}---", str.latin1() );
01850 #endif
01851
01852 if ( d->postDevice ) {
01853 d->bytesTotal += d->postDevice->size();
01854 } else {
01855 d->bytesTotal += d->buffer.size();
01856 d->socket.writeBlock( d->buffer.data(), d->buffer.size() );
01857 d->buffer = QByteArray();
01858 }
01859 }
01860
01861 void Q3Http::slotError( int err )
01862 {
01863 d->postDevice = 0;
01864
01865 if ( d->state == Connecting || d->state == Reading || d->state == Sending ) {
01866 switch ( err ) {
01867 case Q3Socket::ErrConnectionRefused:
01868 finishedWithError( QHttp::tr("Connection refused"), ConnectionRefused );
01869 break;
01870 case Q3Socket::ErrHostNotFound:
01871 finishedWithError( QHttp::tr("Host %1 not found").arg(d->socket.peerName()), HostNotFound );
01872 break;
01873 default:
01874 finishedWithError( QHttp::tr("HTTP request failed"), UnknownError );
01875 break;
01876 }
01877 }
01878
01879 close();
01880 }
01881
01882 void Q3Http::slotBytesWritten( int written )
01883 {
01884 d->bytesDone += written;
01885 emit dataSendProgress( d->bytesDone, d->bytesTotal );
01886
01887 if ( !d->postDevice )
01888 return;
01889
01890 if ( d->socket.bytesToWrite() == 0 ) {
01891 int max = qMin<int>( 4096, d->postDevice->size() - d->postDevice->at() );
01892 QByteArray arr( max );
01893
01894 int n = d->postDevice->readBlock( arr.data(), max );
01895 if ( n != max ) {
01896 qWarning("Could not read enough bytes from the device");
01897 close();
01898 return;
01899 }
01900 if ( d->postDevice->atEnd() ) {
01901 d->postDevice = 0;
01902 }
01903
01904 d->socket.writeBlock( arr.data(), max );
01905 }
01906 }
01907
01908 void Q3Http::slotReadyRead()
01909 {
01910 if ( d->state != Reading ) {
01911 setState( Reading );
01912 d->buffer = QByteArray();
01913 d->readHeader = true;
01914 d->headerStr = "";
01915 d->bytesDone = 0;
01916 d->chunkedSize = -1;
01917 }
01918
01919 while ( d->readHeader ) {
01920 bool end = false;
01921 QString tmp;
01922 while ( !end && d->socket.canReadLine() ) {
01923 tmp = d->socket.readLine();
01924 if ( tmp == "\r\n" || tmp == "\n" )
01925 end = true;
01926 else
01927 d->headerStr += tmp;
01928 }
01929
01930 if ( !end )
01931 return;
01932
01933 #if defined(Q3HTTP_DEBUG)
01934 qDebug( "Q3Http: read response header:\n---{\n%s}---", d->headerStr.latin1() );
01935 #endif
01936 d->response = Q3HttpResponseHeader( d->headerStr );
01937 d->headerStr = "";
01938 #if defined(Q3HTTP_DEBUG)
01939 qDebug( "Q3Http: read response header:\n---{\n%s}---", d->response.toString().latin1() );
01940 #endif
01941
01942 if ( !d->response.isValid() ) {
01943 finishedWithError( QHttp::tr("Invalid HTTP response header"), InvalidResponseHeader );
01944 close();
01945 return;
01946 }
01947
01948
01949
01950
01951 if (d->response.statusCode() != 100) {
01952 d->readHeader = false;
01953 if ( d->response.hasKey( "transfer-encoding" ) &&
01954 d->response.value( "transfer-encoding" ).lower().contains( "chunked" ) )
01955 d->chunkedSize = 0;
01956
01957 emit responseHeaderReceived( d->response );
01958 }
01959 }
01960
01961 if ( !d->readHeader ) {
01962 bool everythingRead = false;
01963
01964 if ( currentRequest().method() == "HEAD" ) {
01965 everythingRead = true;
01966 } else {
01967 Q_ULONG n = d->socket.bytesAvailable();
01968 QByteArray *arr = 0;
01969 if ( d->chunkedSize != -1 ) {
01970
01971 for ( ;; ) {
01972
01973 if ( d->chunkedSize == 0 ) {
01974 if ( !d->socket.canReadLine() )
01975 break;
01976 QString sizeString = d->socket.readLine();
01977 int tPos = sizeString.find( ';' );
01978 if ( tPos != -1 )
01979 sizeString.truncate( tPos );
01980 bool ok;
01981 d->chunkedSize = sizeString.toInt( &ok, 16 );
01982 if ( !ok ) {
01983 finishedWithError( QHttp::tr("Invalid HTTP chunked body"), WrongContentLength );
01984 close();
01985 delete arr;
01986 return;
01987 }
01988 if ( d->chunkedSize == 0 )
01989 d->chunkedSize = -2;
01990 }
01991
01992
01993 while ( d->chunkedSize == -2 && d->socket.canReadLine() ) {
01994 QString read = d->socket.readLine();
01995 if ( read == "\r\n" || read == "\n" )
01996 d->chunkedSize = -1;
01997 }
01998 if ( d->chunkedSize == -1 ) {
01999 everythingRead = true;
02000 break;
02001 }
02002
02003
02004
02005 n = d->socket.bytesAvailable();
02006 if ( n == 0 )
02007 break;
02008 if ( (Q_LONG)n == d->chunkedSize || (Q_LONG)n == d->chunkedSize+1 ) {
02009 n = d->chunkedSize - 1;
02010 if ( n == 0 )
02011 break;
02012 }
02013
02014
02015 uint toRead = QMIN( (Q_LONG)n, (d->chunkedSize < 0 ? (Q_LONG)n : d->chunkedSize) );
02016 if ( !arr )
02017 arr = new QByteArray( 0 );
02018 uint oldArrSize = arr->size();
02019 arr->resize( oldArrSize + toRead );
02020 Q_LONG read = d->socket.readBlock( arr->data()+oldArrSize, toRead );
02021 arr->resize( oldArrSize + read );
02022
02023 d->chunkedSize -= read;
02024
02025 if ( d->chunkedSize == 0 && n - read >= 2 ) {
02026
02027 char tmp[2];
02028 d->socket.readBlock( tmp, 2 );
02029 if ( tmp[0] != '\r' || tmp[1] != '\n' ) {
02030 finishedWithError( QHttp::tr("Invalid HTTP chunked body"), WrongContentLength );
02031 close();
02032 delete arr;
02033 return;
02034 }
02035 }
02036 }
02037 } else if ( d->response.hasContentLength() ) {
02038 n = qMin<ulong>( d->response.contentLength() - d->bytesDone, n );
02039 if ( n > 0 ) {
02040 arr = new QByteArray( n );
02041 Q_LONG read = d->socket.readBlock( arr->data(), n );
02042 arr->resize( read );
02043 }
02044 if ( d->bytesDone + bytesAvailable() + n == d->response.contentLength() )
02045 everythingRead = true;
02046 } else if ( n > 0 ) {
02047
02048 QByteArray temp = d->socket.readAll();
02049 arr = new QByteArray( temp );
02050 }
02051
02052 if ( arr ) {
02053 n = arr->size();
02054 if ( d->toDevice ) {
02055 d->toDevice->writeBlock( arr->data(), n );
02056 delete arr;
02057 d->bytesDone += n;
02058 #if defined(Q3HTTP_DEBUG)
02059 qDebug( "Q3Http::slotReadyRead(): read %ld bytes (%d bytes done)", n, d->bytesDone );
02060 #endif
02061 if ( d->response.hasContentLength() )
02062 emit dataReadProgress( d->bytesDone, d->response.contentLength() );
02063 else
02064 emit dataReadProgress( d->bytesDone, 0 );
02065 } else {
02066 d->rba.append( arr );
02067 #if defined(Q3HTTP_DEBUG)
02068 qDebug( "Q3Http::slotReadyRead(): read %ld bytes (%ld bytes done)", n, d->bytesDone + bytesAvailable() );
02069 #endif
02070 if ( d->response.hasContentLength() )
02071 emit dataReadProgress( d->bytesDone + bytesAvailable(), d->response.contentLength() );
02072 else
02073 emit dataReadProgress( d->bytesDone + bytesAvailable(), 0 );
02074 emit readyRead( d->response );
02075 }
02076 }
02077 }
02078
02079 if ( everythingRead ) {
02080
02081 if ( d->response.value("connection").lower() == "close" ) {
02082 close();
02083 } else {
02084 setState( Connected );
02085
02086
02087 d->idleTimer = startTimer( 0 );
02088 }
02089 }
02090 }
02091 }
02092
02099 Q3Http::State Q3Http::state() const
02100 {
02101 return d->state;
02102 }
02103
02111 Q3Http::Error Q3Http::error() const
02112 {
02113 return d->error;
02114 }
02115
02122 QString Q3Http::errorString() const
02123 {
02124 return d->errorString;
02125 }
02126
02129 void Q3Http::timerEvent( QTimerEvent *e )
02130 {
02131 if ( e->timerId() == d->idleTimer ) {
02132 killTimer( d->idleTimer );
02133 d->idleTimer = 0;
02134
02135 if ( d->state == Connected ) {
02136 finishedWithSuccess();
02137 } else if ( d->state != Unconnected ) {
02138 setState( Unconnected );
02139 finishedWithSuccess();
02140 }
02141 } else {
02142 QObject::timerEvent( e );
02143 }
02144 }
02145
02146 void Q3Http::killIdleTimer()
02147 {
02148 if (d->idleTimer)
02149 killTimer( d->idleTimer );
02150 d->idleTimer = 0;
02151 }
02152
02153 void Q3Http::setState( int s )
02154 {
02155 #if defined(Q3HTTP_DEBUG)
02156 qDebug( "Q3Http state changed %d -> %d", d->state, s );
02157 #endif
02158 d->state = (State)s;
02159 emit stateChanged( s );
02160 }
02161
02162 void Q3Http::close()
02163 {
02164
02165 if ( d->state == Closing || d->state == Unconnected )
02166 return;
02167
02168 d->postDevice = 0;
02169 setState( Closing );
02170
02171
02172 if ( !d->socket.isOpen() ) {
02173 d->idleTimer = startTimer( 0 );
02174 } else {
02175
02176 d->socket.close();
02177
02178
02179 if ( d->socket.state() == Q3Socket::Idle ) {
02180
02181 d->idleTimer = startTimer( 0 );
02182 }
02183 }
02184 }
02185
02186
02187
02188
02189
02190
02193 int Q3Http::supportedOperations() const
02194 {
02195 return OpGet | OpPut;
02196 }
02197
02200 void Q3Http::operationGet( Q3NetworkOperation *op )
02201 {
02202 connect( this, SIGNAL(readyRead(Q3HttpResponseHeader)),
02203 this, SLOT(clientReply(Q3HttpResponseHeader)) );
02204 connect( this, SIGNAL(done(bool)),
02205 this, SLOT(clientDone(bool)) );
02206 connect( this, SIGNAL(stateChanged(int)),
02207 this, SLOT(clientStateChanged(int)) );
02208
02209 bytesRead = 0;
02210 op->setState( StInProgress );
02211 Q3Url u( operationInProgress()->arg( 0 ) );
02212 Q3HttpRequestHeader header( "GET", u.encodedPathAndQuery(), 1, 0 );
02213 header.setValue( "Host", u.host() );
02214 setHost( u.host(), u.port() != -1 ? u.port() : 80 );
02215 request( header );
02216 }
02217
02220 void Q3Http::operationPut( Q3NetworkOperation *op )
02221 {
02222 connect( this, SIGNAL(readyRead(Q3HttpResponseHeader)),
02223 this, SLOT(clientReply(Q3HttpResponseHeader)) );
02224 connect( this, SIGNAL(done(bool)),
02225 this, SLOT(clientDone(bool)) );
02226 connect( this, SIGNAL(stateChanged(int)),
02227 this, SLOT(clientStateChanged(int)) );
02228
02229 bytesRead = 0;
02230 op->setState( StInProgress );
02231 Q3Url u( operationInProgress()->arg( 0 ) );
02232 Q3HttpRequestHeader header( "POST", u.encodedPathAndQuery(), 1, 0 );
02233 header.setValue( "Host", u.host() );
02234 setHost( u.host(), u.port() != -1 ? u.port() : 80 );
02235 request( header, op->rawArg(1) );
02236 }
02237
02238 void Q3Http::clientReply( const Q3HttpResponseHeader &rep )
02239 {
02240 Q3NetworkOperation *op = operationInProgress();
02241 if ( op ) {
02242 if ( rep.statusCode() >= 400 && rep.statusCode() < 600 ) {
02243 op->setState( StFailed );
02244 op->setProtocolDetail(
02245 QString("%1 %2").arg(rep.statusCode()).arg(rep.reasonPhrase())
02246 );
02247 switch ( rep.statusCode() ) {
02248 case 401:
02249 case 403:
02250 case 405:
02251 op->setErrorCode( ErrPermissionDenied );
02252 break;
02253 case 404:
02254 op->setErrorCode(ErrFileNotExisting );
02255 break;
02256 default:
02257 if ( op->operation() == OpGet )
02258 op->setErrorCode( ErrGet );
02259 else
02260 op->setErrorCode( ErrPut );
02261 break;
02262 }
02263 }
02264
02265 if ( op->operation() == OpGet && bytesAvailable() > 0 ) {
02266 QByteArray ba = readAll();
02267 emit data( ba, op );
02268 bytesRead += ba.size();
02269 if ( rep.hasContentLength() ) {
02270 emit dataTransferProgress( bytesRead, rep.contentLength(), op );
02271 }
02272 }
02273 }
02274 }
02275
02276 void Q3Http::clientDone( bool err )
02277 {
02278 disconnect( this, SIGNAL(readyRead(Q3HttpResponseHeader)),
02279 this, SLOT(clientReply(Q3HttpResponseHeader)) );
02280 disconnect( this, SIGNAL(done(bool)),
02281 this, SLOT(clientDone(bool)) );
02282 disconnect( this, SIGNAL(stateChanged(int)),
02283 this, SLOT(clientStateChanged(int)) );
02284
02285 if ( err ) {
02286 Q3NetworkOperation *op = operationInProgress();
02287 if ( op ) {
02288 op->setState( Q3NetworkProtocol::StFailed );
02289 op->setProtocolDetail( errorString() );
02290 switch ( error() ) {
02291 case ConnectionRefused:
02292 op->setErrorCode( ErrHostNotFound );
02293 break;
02294 case HostNotFound:
02295 op->setErrorCode( ErrHostNotFound );
02296 break;
02297 default:
02298 if ( op->operation() == OpGet )
02299 op->setErrorCode( ErrGet );
02300 else
02301 op->setErrorCode( ErrPut );
02302 break;
02303 }
02304 emit finished( op );
02305 }
02306 } else {
02307 Q3NetworkOperation *op = operationInProgress();
02308 if ( op ) {
02309 if ( op->state() != StFailed ) {
02310 op->setState( Q3NetworkProtocol::StDone );
02311 op->setErrorCode( Q3NetworkProtocol::NoError );
02312 }
02313 emit finished( op );
02314 }
02315 }
02316
02317 }
02318
02319 void Q3Http::clientStateChanged( int state )
02320 {
02321 if ( url() ) {
02322 switch ( (State)state ) {
02323 case Connecting:
02324 emit connectionStateChanged( ConHostFound, QHttp::tr( "Host %1 found" ).arg( url()->host() ) );
02325 break;
02326 case Sending:
02327 emit connectionStateChanged( ConConnected, QHttp::tr( "Connected to host %1" ).arg( url()->host() ) );
02328 break;
02329 case Unconnected:
02330 emit connectionStateChanged( ConClosed, QHttp::tr( "Connection to %1 closed" ).arg( url()->host() ) );
02331 break;
02332 default:
02333 break;
02334 }
02335 } else {
02336 switch ( (State)state ) {
02337 case Connecting:
02338 emit connectionStateChanged( ConHostFound, QHttp::tr( "Host found" ) );
02339 break;
02340 case Sending:
02341 emit connectionStateChanged( ConConnected, QHttp::tr( "Connected to host" ) );
02342 break;
02343 case Unconnected:
02344 emit connectionStateChanged( ConClosed, QHttp::tr( "Connection closed" ) );
02345 break;
02346 default:
02347 break;
02348 }
02349 }
02350 }
02351
02352 #endif