00001
00002
00003
00004
00005
00006
00007
00008
00010
00011 #include "httprequest.h"
00012
00013 #include <qregexp.h>
00014 #include <qstringlist.h>
00015 #include <qtextstream.h>
00016 #include <qurl.h>
00017 #include <qfile.h>
00018 #include <qfileinfo.h>
00019
00020 #include "mythconfig.h"
00021 #if defined CONFIG_DARWIN || defined CONFIG_CYGWIN || defined(__FreeBSD__) || defined(USING_MINGW)
00022 #include "darwin-sendfile.h"
00023 #else
00024 #define USE_SETSOCKOPT
00025 #include <sys/sendfile.h>
00026 #endif
00027 #include <sys/types.h>
00028 #include <sys/stat.h>
00029 #include <unistd.h>
00030 #include <stdlib.h>
00031 #include <fcntl.h>
00032
00033 #ifndef USING_MINGW
00034 #include <netinet/tcp.h>
00035 #endif
00036
00037 #include "util.h"
00038 #include "mythcontext.h"
00039 #include "upnp.h"
00040 #include "compat.h"
00041
00042 #ifndef O_LARGEFILE
00043 #define O_LARGEFILE 0
00044 #endif
00045
00046 static MIMETypes g_MIMETypes[] =
00047 {
00048 { "gif" , "image/gif" },
00049 { "jpg" , "image/jpeg" },
00050 { "png" , "image/png" },
00051 { "htm" , "text/html" },
00052 { "html", "text/html" },
00053 { "js" , "text/html" },
00054 { "txt" , "text/plain" },
00055 { "xml" , "text/xml" },
00056 { "pdf" , "application/pdf" },
00057 { "avi" , "video/avi" },
00058 { "css" , "text/css" },
00059 { "swf" , "application/futuresplash" },
00060 { "xls" , "application/vnd.ms-excel" },
00061 { "doc" , "application/vnd.ms-word" },
00062 { "mid" , "audio/midi" },
00063 { "mp3" , "audio/mpeg" },
00064 { "rm" , "application/vnd.rn-realmedia" },
00065 { "wav" , "audio/wav" },
00066 { "zip" , "application/x-tar" },
00067 { "gz" , "application/x-tar" },
00068 { "mpg" , "video/mpeg" },
00069 { "mpeg", "video/mpeg" },
00070 { "ts" , "video/mpegts" },
00071 { "vob" , "video/mpeg" },
00072 { "asf" , "video/x-ms-asf" },
00073 { "nuv" , "video/nupplevideo" },
00074 { "mov" , "video/quicktime" },
00075 { "mp4" , "video/mp4" },
00076 { "mkv" , "video/x-matroska" },
00077 { "mka" , "audio/x-matroska" },
00078 { "wmv" , "video/x-ms-wmv" }
00079 };
00080
00081 static const int g_nMIMELength = sizeof( g_MIMETypes) / sizeof( MIMETypes );
00082 static const int g_on = 1;
00083 static const int g_off = 0;
00084
00085 const char *HTTPRequest::m_szServerHeaders = "Accept-Ranges: bytes\r\n";
00086
00088
00090
00091 HTTPRequest::HTTPRequest() : m_eType ( RequestTypeUnknown ),
00092 m_eContentType ( ContentType_Unknown),
00093 m_nMajor ( 0 ),
00094 m_nMinor ( 0 ),
00095 m_bSOAPRequest ( false ),
00096 m_eResponseType ( ResponseTypeUnknown),
00097 m_nResponseStatus( 200 ),
00098 m_response ( m_aBuffer, IO_WriteOnly ),
00099 m_pPostProcess ( NULL )
00100 {
00101 m_response.setEncoding( QTextStream::UnicodeUTF8 );
00102 }
00103
00105
00107
00108 void HTTPRequest::Reset()
00109 {
00110 m_eType = RequestTypeUnknown;
00111 m_eContentType = ContentType_Unknown;
00112 m_nMajor = 0;
00113 m_nMinor = 0;
00114 m_bSOAPRequest = false;
00115 m_eResponseType = ResponseTypeUnknown;
00116 m_nResponseStatus= 200;
00117 m_pPostProcess = NULL;
00118
00119 m_aBuffer.truncate( 0 );
00120
00121 m_sRawRequest = QString();
00122 m_sBaseUrl = QString();
00123 m_sMethod = QString();
00124
00125 m_mapParams.clear();
00126 m_mapHeaders.clear();
00127
00128 m_sPayload = QString();
00129
00130 m_sProtocol = QString();
00131 m_sNameSpace = QString();
00132
00133 m_mapRespHeaders.clear();
00134
00135 m_sFileName = QString();
00136 }
00137
00139
00141
00142 RequestType HTTPRequest::SetRequestType( const QString &sType )
00143 {
00144 if (sType == "GET" ) return( m_eType = RequestTypeGet );
00145 if (sType == "HEAD" ) return( m_eType = RequestTypeHead );
00146 if (sType == "POST" ) return( m_eType = RequestTypePost );
00147 if (sType == "M-SEARCH" ) return( m_eType = RequestTypeMSearch );
00148
00149 if (sType == "SUBSCRIBE" ) return( m_eType = RequestTypeSubscribe );
00150 if (sType == "UNSUBSCRIBE") return( m_eType = RequestTypeUnsubscribe );
00151 if (sType == "NOTIFY" ) return( m_eType = RequestTypeNotify );
00152
00153 if (sType.startsWith( "HTTP/" )) return( m_eType = RequestTypeResponse );
00154
00155 VERBOSE( VB_UPNP, QString( "HTTPRequest::SentRequestType( %1 ) - returning Unknown." )
00156 .arg( sType ) );
00157
00158 return( m_eType = RequestTypeUnknown);
00159 }
00160
00162
00164
00165 QString HTTPRequest::BuildHeader( long long nSize )
00166 {
00167 QString sHeader;
00168 QString sContentType = (m_eResponseType == ResponseTypeOther) ?
00169 m_sResponseTypeText : GetResponseType();
00170
00171 sHeader = QString( "HTTP/%1.%2 %3\r\n"
00172 "Date: %4\r\n"
00173 "Server: %5, UPnP/1.0, MythTV %6\r\n" )
00174 .arg( m_nMajor )
00175 .arg( m_nMinor )
00176 .arg( GetResponseStatus() )
00177 .arg( QDateTime::currentDateTime().toString( "d MMM yyyy hh:mm:ss" ) )
00178 .arg( HttpServer::g_sPlatform )
00179 .arg( MYTH_BINARY_VERSION );
00180
00181 sHeader += GetAdditionalHeaders();
00182
00183
00184
00185
00186 QString sValue = GetHeaderValue( "getcontentfeatures.dlna.org", "0" );
00187
00188 if (sValue == "1")
00189 sHeader += "contentFeatures.dlna.org: DLNA.ORG_OP=01;DLNA.ORG_CI=0;"
00190 "DLNA.ORG_FLAGS=01500000000000000000000000000000\r\n";
00191
00192
00193
00194 sHeader += QString( "Connection: %1\r\n"
00195 "Content-Type: %2\r\n"
00196 "Content-Length: %3\r\n" )
00197 .arg( GetKeepAlive() ? "Keep-Alive" : "Close" )
00198 .arg( sContentType )
00199 .arg( nSize );
00200 sHeader += "\r\n";
00201
00202 return sHeader;
00203 }
00204
00206
00208
00209 long HTTPRequest::SendResponse( void )
00210 {
00211 long nBytes = 0;
00212 QCString sHeader;
00213
00214 switch( m_eResponseType )
00215 {
00216 case ResponseTypeUnknown:
00217 case ResponseTypeNone:
00218 VERBOSE(VB_UPNP,QString("HTTPRequest::SendResponse( None ) :%1 -> %2:")
00219 .arg(GetResponseStatus())
00220 .arg(GetPeerAddress()));
00221 return( -1 );
00222
00223 case ResponseTypeFile:
00224 VERBOSE(VB_UPNP,QString("HTTPRequest::SendResponse( File ) :%1 -> %2:")
00225 .arg(GetResponseStatus())
00226 .arg(GetPeerAddress()));
00227
00228 return( SendResponseFile( m_sFileName ));
00229
00230 case ResponseTypeXML:
00231 case ResponseTypeHTML:
00232 case ResponseTypeOther:
00233 default:
00234 break;
00235 }
00236
00237 VERBOSE(VB_UPNP,QString("HTTPRequest::SendResponse(xml/html) (%1) :%2 -> %3: %4")
00238 .arg(m_sFileName)
00239 .arg(GetResponseStatus())
00240 .arg(GetPeerAddress())
00241 .arg(m_eResponseType));
00242
00243
00244
00245
00246
00247 #ifdef USE_SETSOCKOPT
00248
00249 setsockopt( getSocketHandle(), SOL_TCP, TCP_CORK, &g_on, sizeof( g_on ));
00250 #endif
00251
00252
00253
00254
00255
00256 sHeader = BuildHeader ( m_aBuffer.size() ).utf8();
00257 nBytes = WriteBlockDirect( sHeader.data(), sHeader.length() );
00258
00259
00260
00261
00262
00263 if (( m_eType != RequestTypeHead ) && ( m_aBuffer.size() > 0 ))
00264 {
00265
00266
00267
00268
00269
00270
00271
00272
00273 nBytes += WriteBlockDirect( m_aBuffer.data(), m_aBuffer.size() );
00274 }
00275
00276
00277
00278
00279
00280 #ifdef USE_SETSOCKOPT
00281 setsockopt( getSocketHandle(), SOL_TCP, TCP_CORK, &g_off, sizeof( g_off ));
00282 #endif
00283
00284 return( nBytes );
00285 }
00286
00288
00290
00291 long HTTPRequest::SendResponseFile( QString sFileName )
00292 {
00293 QCString sHeader;
00294 long nBytes = 0;
00295 long long llSize = 0;
00296 long long llStart = 0;
00297 long long llEnd = 0;
00298
00299 VERBOSE(VB_UPNP, QString("SendResponseFile ( %1 )").arg(sFileName));
00300
00301 m_eResponseType = ResponseTypeOther;
00302 m_sResponseTypeText = "text/plain";
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318 #ifdef USE_SETSOCKOPT
00319
00320 setsockopt( getSocketHandle(), SOL_TCP, TCP_CORK, &g_on, sizeof( g_on ));
00321 #endif
00322
00323 if (QFile::exists( sFileName ))
00324 {
00325 QFileInfo info( sFileName );
00326
00327 m_sResponseTypeText = GetMimeType( info.extension( FALSE ).lower() );
00328
00329
00330
00331
00332
00333 struct stat st;
00334
00335 if (stat( sFileName.ascii(), &st ) == 0)
00336 llSize = llEnd = st.st_size;
00337
00338 m_nResponseStatus = 200;
00339
00340
00341
00342
00343
00344 bool bRange = false;
00345 QString sRange = GetHeaderValue( "range", "" );
00346
00347 if (sRange.length() > 0)
00348 {
00349 bRange = ParseRange( sRange, llSize, &llStart, &llEnd );
00350 if ((llSize >= llStart) && (llSize >= llEnd) && (llEnd >= llStart))
00351 {
00352 if (bRange)
00353 {
00354 m_nResponseStatus = 206;
00355 m_mapRespHeaders[ "Content-Range" ] = QString("bytes %1-%2/%3")
00356 .arg( llStart )
00357 .arg( llEnd )
00358 .arg( llSize );
00359 llSize = (llEnd - llStart) + 1;
00360 }
00361 }
00362 else
00363 {
00364 m_nResponseStatus = 416;
00365 llSize = 0;
00366 VERBOSE(VB_UPNP,
00367 QString("HTTPRequest::SendResponseFile(%1) - invalid byte range %2-%3/%4")
00368 .arg(sFileName)
00369 .arg(llStart)
00370 .arg(llEnd)
00371 .arg(llSize));
00372 }
00373 }
00374
00375
00376
00377 if (bRange == false)
00378 m_mapRespHeaders[ "User-Agent" ] = "redsonic";
00379
00380
00381
00382
00383
00384 }
00385 else
00386 {
00387 VERBOSE(VB_UPNP,
00388 QString("HTTPRequest::SendResponseFile(%1) - cannot find file!")
00389 .arg(sFileName));
00390 m_nResponseStatus = 404;
00391 }
00392
00393
00394
00395
00396
00397
00398
00399 sHeader = BuildHeader( llSize ).utf8();
00400 nBytes = WriteBlockDirect( sHeader.data(), sHeader.length() );
00401
00402
00403
00404
00405
00406
00407 if (( m_eType != RequestTypeHead ) && (llSize != 0))
00408 {
00409 __off64_t offset = llStart;
00410 int file = open( sFileName.ascii(), O_RDONLY | O_LARGEFILE );
00411 ssize_t sent = 0;
00412
00413 do
00414 {
00415
00416
00417
00418 sent = sendfile64( getSocketHandle(), file, &offset,
00419 (size_t)(llSize > INT_MAX ? INT_MAX : llSize));
00420
00421 llSize = llEnd - offset;
00422
00423 }
00424 while (( sent >= 0 ) && ( llSize > 0 ));
00425
00426 if (sent == -1)
00427 {
00428 VERBOSE(VB_UPNP,QString("SendResponseFile( %1 ) Error: %2 [%3]" )
00429 .arg( sFileName )
00430 .arg( errno )
00431 .arg( strerror( errno ) ));
00432
00433 nBytes = -1;
00434 }
00435
00436 close( file );
00437 }
00438
00439
00440
00441
00442
00443 #ifdef USE_SETSOCKOPT
00444 setsockopt( getSocketHandle(), SOL_TCP, TCP_CORK, &g_off, sizeof( g_off ));
00445 #endif
00446
00447
00448
00449
00450 return nBytes;
00451 }
00452
00454
00456
00457 void HTTPRequest::FormatErrorResponse( bool bServerError,
00458 const QString &sFaultString,
00459 const QString &sDetails )
00460 {
00461 m_eResponseType = ResponseTypeXML;
00462 m_nResponseStatus = 500;
00463
00464 m_response << "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
00465
00466 QString sWhere = ( bServerError ) ? "s:Server" : "s:Client";
00467
00468 if (m_bSOAPRequest)
00469 {
00470 m_mapRespHeaders[ "EXT" ] = "";
00471
00472 m_response << SOAP_ENVELOPE_BEGIN
00473 << "<s:Fault>"
00474 << "<faultcode>" << sWhere << "</faultcode>"
00475 << "<faultstring>" << sFaultString << "</faultstring>";
00476 }
00477
00478 if (sDetails.length() > 0)
00479 {
00480 m_response << "<detail>" << sDetails << "</detail>";
00481 }
00482
00483 if (m_bSOAPRequest)
00484 m_response << "</s:Fault>" << SOAP_ENVELOPE_END;
00485 }
00486
00488
00490
00491 void HTTPRequest::FormatActionResponse( NameValueList *pArgs )
00492 {
00493 m_eResponseType = ResponseTypeXML;
00494 m_nResponseStatus = 200;
00495
00496 m_response << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n";
00497
00498 if (m_bSOAPRequest)
00499 {
00500 m_mapRespHeaders[ "EXT" ] = "";
00501
00502 m_response << SOAP_ENVELOPE_BEGIN
00503 << "<u:" << m_sMethod << "Response xmlns:u=\"" << m_sNameSpace << "\">\r\n";
00504 }
00505 else
00506 m_response << "<" << m_sMethod << "Response>\r\n";
00507
00508 for (NameValue *pNV = pArgs->first(); pNV != NULL; pNV = pArgs->next())
00509 {
00510 m_response << "<" << pNV->sName;
00511
00512 if (pNV->pAttributes != NULL)
00513 {
00514
00515 for (NameValue *pAttr = pNV->pAttributes->first();
00516 pAttr != NULL;
00517 pAttr = pNV->pAttributes->next())
00518 {
00519 m_response << " " << pAttr->sName << "='" << Encode( pAttr->sValue ) << "'";
00520 }
00521 }
00522
00523 m_response << ">";
00524
00525 if (m_bSOAPRequest)
00526 m_response << Encode( pNV->sValue );
00527 else
00528 m_response << pNV->sValue;
00529
00530 m_response << "</" << pNV->sName << ">\r\n";
00531 }
00532
00533 if (m_bSOAPRequest)
00534 {
00535 m_response << "</u:" << m_sMethod << "Response>\r\n"
00536 << SOAP_ENVELOPE_END;
00537 }
00538 else
00539 m_response << "</" << m_sMethod << "Response>\r\n";
00540 }
00541
00543
00545
00546 void HTTPRequest::FormatFileResponse( const QString &sFileName )
00547 {
00548 m_sFileName = sFileName;
00549
00550 if (QFile::exists( m_sFileName ))
00551 {
00552
00553 m_eResponseType = ResponseTypeFile;
00554 m_nResponseStatus = 200;
00555 m_mapRespHeaders[ "Cache-Control" ] = "no-cache=\"Ext\", max-age = 5000";
00556 }
00557 else
00558 {
00559 m_eResponseType = ResponseTypeHTML;
00560 m_nResponseStatus = 404;
00561 VERBOSE(VB_UPNP, QString("HTTPRequest::FormatFileResponse(%1) - cannot find file").arg(sFileName));
00562 }
00563 }
00564
00566
00568
00569 void HTTPRequest::SetRequestProtocol( const QString &sLine )
00570 {
00571 m_sProtocol = sLine.section( '/', 0, 0 ).stripWhiteSpace();
00572 QString sVersion = sLine.section( '/', 1 ).stripWhiteSpace();
00573
00574 m_nMajor = sVersion.section( '.', 0, 0 ).toInt();
00575 m_nMinor = sVersion.section( '.', 1 ).toInt();
00576 }
00577
00579
00581
00582 ContentType HTTPRequest::SetContentType( const QString &sType )
00583 {
00584 if (sType == "application/x-www-form-urlencoded") return( m_eContentType = ContentType_Urlencoded );
00585 if (sType == "text/xml" ) return( m_eContentType = ContentType_XML );
00586
00587 return( m_eContentType = ContentType_Unknown );
00588 }
00589
00590
00592
00594
00595 QString HTTPRequest::GetResponseStatus( void )
00596 {
00597 switch( m_nResponseStatus )
00598 {
00599 case 200: return( "200 OK" );
00600 case 201: return( "201 Created" );
00601 case 202: return( "202 Accepted" );
00602 case 206: return( "206 Partial Content" );
00603 case 400: return( "400 Bad Request" );
00604 case 401: return( "401 Unauthorized" );
00605 case 403: return( "403 Forbidden" );
00606 case 404: return( "404 Not Found" );
00607 case 405: return( "405 Method Not Allowed" );
00608 case 406: return( "406 Not Acceptable" );
00609 case 408: return( "408 Request Timeout" );
00610 case 412: return( "412 Precondition Failed" );
00611 case 413: return( "413 Request Entity Too Large" );
00612 case 414: return( "414 Request-URI Too Long" );
00613 case 415: return( "415 Unsupported Media Type" );
00614 case 416: return( "416 Requested Range Not Satisfiable" );
00615 case 417: return( "417 Expectation Failed" );
00616 case 500: return( "500 Internal Server Error" );
00617 case 501: return( "501 Not Implemented" );
00618 case 502: return( "502 Bad Gateway" );
00619 case 503: return( "503 Service Unavailable" );
00620 case 504: return( "504 Gateway Timeout" );
00621 case 505: return( "505 HTTP Version Not Supported" );
00622 case 510: return( "510 Not Extended" );
00623 }
00624
00625 return( QString( "%1 Unknown" ).arg( m_nResponseStatus ));
00626 }
00627
00629
00631
00632 QString HTTPRequest::GetResponseType( void )
00633 {
00634 switch( m_eResponseType )
00635 {
00636 case ResponseTypeXML : return( "text/xml; charset=\"UTF-8\"" );
00637 case ResponseTypeHTML : return( "text/html; charset=\"UTF-8\"" );
00638 default: break;
00639 }
00640
00641 return( "text/plain" );
00642 }
00643
00645
00647
00648 QString HTTPRequest::GetMimeType( const QString &sFileExtension )
00649 {
00650 QString ext;
00651
00652 for (int i = 0; i < g_nMIMELength; i++)
00653 {
00654 ext = g_MIMETypes[i].pszExtension;
00655
00656 if ( sFileExtension.upper() == ext.upper() )
00657 return( g_MIMETypes[i].pszType );
00658 }
00659
00660 return( "text/plain" );
00661 }
00662
00664
00666
00667 long HTTPRequest::GetParameters( QString sParams, QStringMap &mapParams )
00668 {
00669 long nCount = 0;
00670
00671 sParams.replace( "%26", "&" );
00672
00673 if (sParams.length() > 0)
00674 {
00675 QStringList params = QStringList::split( "&", sParams );
00676
00677 for ( QStringList::Iterator it = params.begin();
00678 it != params.end(); ++it )
00679 {
00680 QString sName = (*it).section( '=', 0, 0 );
00681 QString sValue = (*it).section( '=', 1 );
00682
00683 if ((sName.length() != 0) && (sValue.length() !=0))
00684 {
00685 QUrl::decode( sName );
00686 QUrl::decode( sValue );
00687
00688 mapParams.insert( sName.stripWhiteSpace(), sValue );
00689 nCount++;
00690 }
00691 }
00692 }
00693
00694 return nCount;
00695 }
00696
00697
00699
00701
00702 QString HTTPRequest::GetHeaderValue( const QString &sKey, QString sDefault )
00703 {
00704 QStringMap::iterator it = m_mapHeaders.find( sKey.lower() );
00705
00706 if ( it == m_mapHeaders.end())
00707 return( sDefault );
00708
00709 return( it.data() );
00710 }
00711
00712
00714
00716
00717 QString HTTPRequest::GetAdditionalHeaders( void )
00718 {
00719 QString sHeader = m_szServerHeaders;
00720
00721 for ( QStringMap::iterator it = m_mapRespHeaders.begin();
00722 it != m_mapRespHeaders.end();
00723 ++it )
00724 {
00725 sHeader += it.key() + ": ";
00726 sHeader += it.data() + "\r\n";
00727 }
00728
00729 return( sHeader );
00730 }
00731
00733
00735
00736 bool HTTPRequest::GetKeepAlive()
00737 {
00738 bool bKeepAlive = true;
00739
00740
00741
00742 if ((m_nMajor == 1) && (m_nMinor == 0))
00743 bKeepAlive = false;
00744
00745
00746
00747 QString sConnection = GetHeaderValue( "connection", "default" ).lower();
00748
00749 if ( sConnection == "close" )
00750 bKeepAlive = false;
00751 else if (sConnection == "keep-alive")
00752 bKeepAlive = true;
00753
00754 return bKeepAlive;
00755 }
00756
00758
00760
00761 bool HTTPRequest::ParseRequest()
00762 {
00763 bool bSuccess = false;
00764
00765 try
00766 {
00767
00768
00769 QString sRequestLine = ReadLine( 2000 );
00770
00771 if ( sRequestLine.length() == 0)
00772 {
00773 VERBOSE(VB_IMPORTANT, "HTTPRequest::ParseRequest - Timeout reading first line of request." );
00774 return false;
00775 }
00776
00777
00778
00779 ProcessRequestLine( sRequestLine );
00780
00781
00782
00783 m_mapHeaders[ "content-length" ] = "0";
00784 m_mapHeaders[ "content-type" ] = "unknown";
00785
00786
00787
00788 bool bDone = false;
00789 QString sLine = ReadLine( 2000 );
00790
00791 while (( sLine.length() > 0 ) && !bDone )
00792 {
00793 if (sLine != "\r\n")
00794 {
00795 QString sName = sLine.section( ':', 0, 0 ).stripWhiteSpace();
00796 QString sValue = sLine.section( ':', 1 );
00797
00798 sValue.truncate( sValue.length() - 2 );
00799
00800 if ((sName.length() != 0) && (sValue.length() !=0))
00801 m_mapHeaders.insert( sName.lower(), sValue.stripWhiteSpace() );
00802
00803 sLine = ReadLine( 2000 );
00804
00805 }
00806 else
00807 bDone = true;
00808
00809 }
00810
00811
00812
00813 if (!bDone)
00814 {
00815 VERBOSE(VB_IMPORTANT, "HTTPRequest::ParseRequest - Timeout waiting for request header." );
00816 return false;
00817 }
00818
00819 bSuccess = true;
00820
00821 SetContentType( m_mapHeaders[ "content-type" ] );
00822
00823
00824
00825 long nPayloadSize = m_mapHeaders[ "content-length" ].toLong();
00826
00827 if (nPayloadSize > 0)
00828 {
00829 char *pszPayload = new char[ nPayloadSize + 2 ];
00830 long nBytes = 0;
00831
00832 if (( nBytes = ReadBlock( pszPayload, nPayloadSize, 5000 )) == nPayloadSize )
00833 {
00834 m_sPayload = QString::fromUtf8( pszPayload, nPayloadSize );
00835
00836
00837
00838 if ( m_eContentType == ContentType_Urlencoded)
00839 GetParameters( m_sPayload, m_mapParams );
00840 }
00841 else
00842 {
00843 VERBOSE( VB_IMPORTANT, QString( "HTTPRequest::ParseRequest - Unable to read entire payload (read %1 of %2 bytes" )
00844 .arg( nBytes )
00845 .arg( nPayloadSize ) );
00846 bSuccess = false;
00847 }
00848
00849 delete [] pszPayload;
00850 }
00851
00852
00853
00854 QString sSOAPAction = GetHeaderValue( "SOAPACTION", "" );
00855
00856 if (sSOAPAction.length() > 0)
00857 bSuccess = ProcessSOAPPayload( sSOAPAction );
00858 else
00859 ExtractMethodFromURL();
00860
00861
00862
00863
00864
00865
00866
00867
00868
00869 }
00870 catch( ... )
00871 {
00872 VERBOSE(VB_IMPORTANT, "Unexpected exception in HTTPRequest::ParseRequest" );
00873 }
00874
00875 return bSuccess;
00876 }
00877
00879
00881
00882 void HTTPRequest::ProcessRequestLine( const QString &sLine )
00883 {
00884
00885 m_sRawRequest = sLine;
00886
00887 QString sToken;
00888 QStringList tokens = QStringList::split(QRegExp("[ \r\n][ \r\n]*"), sLine );
00889 int nCount = tokens.count();
00890
00891
00892
00893 if ( sLine.startsWith( "HTTP/" ))
00894 m_eType = RequestTypeResponse;
00895 else
00896 m_eType = RequestTypeUnknown;
00897
00898
00899
00900
00901
00902
00903
00904
00905 if (m_eType != RequestTypeResponse)
00906 {
00907
00908
00909
00910
00911 if (nCount > 0)
00912 SetRequestType( tokens[0].stripWhiteSpace() );
00913
00914 if (nCount > 1)
00915 {
00916 m_sBaseUrl = tokens[1].section( '?', 0, 0).stripWhiteSpace();
00917
00918
00919
00920 QString sQueryStr = tokens[1].section( '?', 1, 1 );
00921
00922 if (sQueryStr.length() > 0)
00923 GetParameters( sQueryStr, m_mapParams );
00924
00925 }
00926
00927 if (nCount > 2)
00928 SetRequestProtocol( tokens[2].stripWhiteSpace() );
00929 }
00930 else
00931 {
00932
00933
00934
00935
00936 if (nCount > 0)
00937 SetRequestProtocol( tokens[0].stripWhiteSpace() );
00938
00939 if (nCount > 1)
00940 m_nResponseStatus = tokens[1].toInt();
00941 }
00942 }
00943
00945
00947
00948 bool HTTPRequest::ParseRange( QString sRange,
00949 long long llSize,
00950 long long *pllStart,
00951 long long *pllEnd )
00952 {
00953
00954
00955
00956
00957 if (sRange.length() == 0)
00958 return false;
00959
00960
00961
00962
00963
00964 int nIdx = sRange.find( QRegExp( "(\\d|\\-)") );
00965
00966 if (nIdx < 0)
00967 return false;
00968
00969 if (nIdx > 0)
00970 sRange.remove( 0, nIdx );
00971
00972
00973
00974
00975
00976 QStringList ranges = QStringList::split( ",", sRange );
00977
00978 if (ranges.count() == 0)
00979 return false;
00980
00981
00982
00983
00984
00985 QStringList parts = QStringList::split( "-", ranges[0], true );
00986
00987 if (parts.count() != 2)
00988 return false;
00989
00990 if (parts[0].isNull() && parts[1].isNull())
00991 return false;
00992
00993
00994
00995
00996
00997 if (parts[0].isNull())
00998 {
00999
01000
01001
01002
01003 long long llValue = strtoll( parts[1], NULL, 10 );
01004
01005 *pllStart = llSize - llValue;
01006 *pllEnd = llSize - 1;
01007 }
01008 else if (parts[1].isNull())
01009 {
01010
01011
01012
01013
01014 *pllStart = strtoll( parts[0], NULL, 10 );
01015
01016 if (*pllStart == 0)
01017 return false;
01018
01019 *pllEnd = llSize - 1;
01020 }
01021 else
01022 {
01023
01024
01025
01026
01027 *pllStart = strtoll( parts[0], NULL, 10 );
01028 *pllEnd = strtoll( parts[1], NULL, 10 );
01029
01030 if (*pllStart > *pllEnd)
01031 return false;
01032 }
01033
01034
01035
01036 return true;
01037 }
01038
01040
01042
01043 void HTTPRequest::ExtractMethodFromURL()
01044 {
01045 QStringList sList = QStringList::split( "/", m_sBaseUrl, false );
01046
01047 m_sMethod = "";
01048
01049 if (sList.size() > 0)
01050 {
01051 m_sMethod = sList.last();
01052 sList.pop_back();
01053 }
01054
01055 m_sBaseUrl = "/" + sList.join( "/" );
01056
01057 }
01058
01060
01062
01063 bool HTTPRequest::ProcessSOAPPayload( const QString &sSOAPAction )
01064 {
01065 bool bSuccess = false;
01066
01067
01068
01069
01070
01071 VERBOSE(VB_UPNP, QString("HTTPRequest::ProcessSOAPPayload : %1 : ").arg(sSOAPAction));
01072 QDomDocument doc ( "request" );
01073
01074 QString sErrMsg;
01075 int nErrLine = 0;
01076 int nErrCol = 0;
01077
01078 if (!doc.setContent( m_sPayload, true, &sErrMsg, &nErrLine, &nErrCol ))
01079 {
01080 VERBOSE(VB_IMPORTANT, QString( "Error parsing request at line: %1 column: %2 : %3" )
01081 .arg( nErrLine )
01082 .arg( nErrCol )
01083 .arg( sErrMsg ));
01084 return( false );
01085 }
01086
01087
01088
01089
01090
01091 m_sNameSpace = sSOAPAction.section( "#", 0, 0).remove( 0, 1);
01092 m_sMethod = sSOAPAction.section( "#", 1 );
01093 m_sMethod.remove( m_sMethod.length()-1, 1 );
01094
01095 QDomNodeList oNodeList = doc.elementsByTagNameNS( m_sNameSpace, m_sMethod );
01096
01097 if (oNodeList.count() > 0)
01098 {
01099 QDomNode oMethod = oNodeList.item(0);
01100
01101 if (!oMethod.isNull())
01102 {
01103 m_bSOAPRequest = true;
01104
01105 for ( QDomNode oNode = oMethod.firstChild(); !oNode.isNull();
01106 oNode = oNode.nextSibling() )
01107 {
01108 QDomElement e = oNode.toElement();
01109
01110 if (!e.isNull())
01111 {
01112 QString sName = e.tagName();
01113 QString sValue = "";
01114
01115 QDomText oText = oNode.firstChild().toText();
01116
01117 if (!oText.isNull())
01118 sValue = oText.nodeValue();
01119
01120 QUrl::decode( sName );
01121 QUrl::decode( sValue );
01122
01123 m_mapParams.insert( sName.stripWhiteSpace(), sValue );
01124 }
01125 }
01126
01127 bSuccess = true;
01128 }
01129 }
01130
01131 return bSuccess;
01132 }
01133
01135
01137
01138 QString &HTTPRequest::Encode( QString &sStr )
01139 {
01140
01141 sStr.replace(QRegExp( "&"), "&" );
01142 sStr.replace(QRegExp( "<"), "<" );
01143 sStr.replace(QRegExp( ">"), ">" );
01144 sStr.replace(QRegExp("\""), """);
01145 sStr.replace(QRegExp( "'"), "'");
01146
01147 return( sStr );
01148 }
01149
01152
01153
01154
01157
01158 BufferedSocketDeviceRequest::BufferedSocketDeviceRequest( BufferedSocketDevice *pSocket )
01159 {
01160 m_pSocket = pSocket;
01161 }
01162
01164
01166
01167 Q_LONG BufferedSocketDeviceRequest::BytesAvailable()
01168 {
01169 if (m_pSocket)
01170 return( m_pSocket->BytesAvailable() );
01171
01172 return( 0 );
01173 }
01174
01176
01178
01179 Q_ULONG BufferedSocketDeviceRequest::WaitForMore( int msecs, bool *timeout )
01180 {
01181 if (m_pSocket)
01182 return( m_pSocket->WaitForMore( msecs, timeout ));
01183
01184 return( 0 );
01185 }
01186
01188
01190
01191 bool BufferedSocketDeviceRequest::CanReadLine()
01192 {
01193 if (m_pSocket)
01194 return( m_pSocket->CanReadLine() );
01195
01196 return( false );
01197 }
01198
01200
01202
01203 QString BufferedSocketDeviceRequest::ReadLine( int msecs )
01204 {
01205 QString sLine;
01206
01207 if (m_pSocket)
01208 sLine = m_pSocket->ReadLine( msecs );
01209
01210 return( sLine );
01211 }
01212
01214
01216
01217 Q_LONG BufferedSocketDeviceRequest::ReadBlock( char *pData, Q_ULONG nMaxLen, int msecs )
01218 {
01219 if (m_pSocket)
01220 {
01221 if (msecs == 0)
01222 return( m_pSocket->ReadBlock( pData, nMaxLen ));
01223 else
01224 {
01225 bool bTimeout = false;
01226
01227 while ( (BytesAvailable() < (int)nMaxLen) && !bTimeout )
01228 m_pSocket->WaitForMore( msecs, &bTimeout );
01229
01230
01231
01232 return( m_pSocket->ReadBlock( pData, nMaxLen ));
01233 }
01234 }
01235
01236 return( -1 );
01237 }
01238
01240
01242
01243 Q_LONG BufferedSocketDeviceRequest::WriteBlock( char *pData, Q_ULONG nLen )
01244 {
01245 if (m_pSocket)
01246 return( m_pSocket->WriteBlock( pData, nLen ));
01247
01248 return( -1 );
01249 }
01250
01252
01254
01255 Q_LONG BufferedSocketDeviceRequest::WriteBlockDirect( char *pData, Q_ULONG nLen )
01256 {
01257 if (m_pSocket)
01258 return( m_pSocket->WriteBlockDirect( pData, nLen ));
01259
01260 return( -1 );
01261 }
01262
01264
01266
01267 QString BufferedSocketDeviceRequest::GetHostAddress()
01268 {
01269 return( m_pSocket->SocketDevice()->address().toString() );
01270 }
01271
01273
01275
01276 QString BufferedSocketDeviceRequest::GetPeerAddress()
01277 {
01278 return( m_pSocket->SocketDevice()->peerAddress().toString() );
01279 }
01280
01282
01284
01285 void BufferedSocketDeviceRequest::SetBlocking( bool bBlock )
01286 {
01287 if (m_pSocket)
01288 return( m_pSocket->SocketDevice()->setBlocking( bBlock ));
01289 }
01290
01292
01294
01295 bool BufferedSocketDeviceRequest::IsBlocking()
01296 {
01297 if (m_pSocket)
01298 return( m_pSocket->SocketDevice()->blocking());
01299
01300 return false;
01301 }