|
MythTV
0.26-pre
|
00001 #include <iostream> 00002 using namespace std; 00003 00004 #include <QCoreApplication> 00005 #include <QRegExp> 00006 #include <QTimer> 00007 #include <QFile> 00008 00009 #include "mythlogging.h" 00010 #include "compat.h" 00011 #include "mcodecs.h" 00012 #include "httpcomms.h" 00013 00014 HttpComms::HttpComms() 00015 : http(0) 00016 { 00017 init(); 00018 } 00019 00020 00021 HttpComms::HttpComms(QUrl &url, int timeoutms) 00022 : http(0) 00023 { 00024 init(); 00025 request(url, timeoutms); 00026 } 00027 00028 HttpComms::HttpComms(QUrl &url, QHttpRequestHeader &header, int timeoutms) 00029 { 00030 init(); 00031 request(url, header, timeoutms); 00032 } 00033 00034 HttpComms::~HttpComms() 00035 { 00036 if (m_timer) 00037 { 00038 m_timer->disconnect(); 00039 m_timer->deleteLater(); 00040 m_timer = NULL; 00041 } 00042 00043 delete http; 00044 } 00045 00046 void HttpComms::init() 00047 { 00048 // m_curRequest = NULL; 00049 m_authNeeded = false; 00050 http = new QHttp(); 00051 m_done = false; 00052 m_statusCode = 0; 00053 m_timer = NULL; 00054 m_timeout = false; 00055 m_progress = m_total = 0; 00056 00057 00058 connect(http, SIGNAL(done(bool)), this, SLOT(done(bool))); 00059 connect(http, SIGNAL(stateChanged(int)), this, SLOT(stateChanged(int))); 00060 connect(http, SIGNAL(responseHeaderReceived(const QHttpResponseHeader &)), 00061 this, SLOT(headerReceived(const QHttpResponseHeader &))); 00062 connect(http, SIGNAL(dataReadProgress(int, int)), this, SLOT(dataReadProgress(int, int))); 00063 00064 } 00065 00066 void HttpComms::request(QUrl &url, int timeoutms, bool allowGzip) 00067 { 00068 QString path = url.path(); 00069 00070 if (url.hasQuery()) 00071 path += '?' + url.encodedQuery(); 00072 00073 QHttpRequestHeader header("GET", path); 00074 QString userAgent = "Mozilla/9.876 (X11; U; Linux 2.2.12-20 i686, en) " 00075 "Gecko/25250101 Netscape/5.432b1"; 00076 00077 header.setValue("Host", url.host()); 00078 header.setValue("User-Agent", userAgent); 00079 00080 if (allowGzip) 00081 header.setValue( "Accept-Encoding", "gzip"); 00082 00083 request(url, header, timeoutms); 00084 } 00085 00086 00087 00088 void HttpComms::request(QUrl &url, 00089 QHttpRequestHeader &header, 00090 int timeoutms, 00091 QIODevice *pData /* = NULL*/ ) 00092 { 00093 quint16 port = 80; 00094 00095 if (url.port() != -1) 00096 port = url.port(); 00097 00098 http->setHost(url.host(), port); 00099 00100 m_url = url.toString(); 00101 m_curRequest = header; 00102 00103 if (m_timer) 00104 m_timer->stop(); 00105 00106 if (timeoutms > 0 ) 00107 { 00108 if (!m_timer) 00109 { 00110 m_timer = new QTimer(); 00111 connect(m_timer, SIGNAL(timeout()), SLOT(timeout())); 00112 } 00113 m_timeoutInterval = timeoutms; 00114 m_timer->setSingleShot(true); 00115 m_timer->start(timeoutms); 00116 } 00117 00118 if (!m_cookie.isEmpty()) 00119 { 00120 header.setValue("Cookie", m_cookie); 00121 } 00122 00123 http->request(header, pData); 00124 } 00125 00126 void HttpComms::stop() 00127 { 00128 disconnect(http, 0, 0, 0); 00129 http->abort(); 00130 00131 if (m_timer) 00132 m_timer->stop(); 00133 } 00134 00135 void HttpComms::done(bool error) 00136 { 00137 if (error) 00138 { 00139 LOG(VB_GENERAL, LOG_ERR, 00140 QString("NetworkOperation Error on Finish: %1 (%2): url: '%3'") 00141 .arg(http->errorString()) .arg(error) .arg(m_url.toString())); 00142 } 00143 else if (m_authNeeded) 00144 { 00145 LOG(VB_NETWORK, LOG_ERR, QString("Authentication pending, ignoring " 00146 "done from first request.")); 00147 return; 00148 } 00149 else if (http->bytesAvailable()) 00150 { 00151 m_data.resize(http->bytesAvailable()); 00152 m_data = http->readAll(); 00153 } 00154 00155 LOG(VB_NETWORK, LOG_DEBUG, QString("done: %1 bytes").arg(m_data.size())); 00156 00157 if (m_timer) 00158 m_timer->stop(); 00159 00160 m_done = true; 00161 } 00162 00163 void HttpComms::stateChanged(int state) 00164 { 00165 QString stateStr; 00166 00167 switch (state) 00168 { 00169 case QHttp::Unconnected: stateStr = "unconnected"; break; 00170 case QHttp::HostLookup: stateStr = "host lookup"; break; 00171 case QHttp::Connecting: stateStr = "connecting"; break; 00172 case QHttp::Sending: stateStr = "sending"; break; 00173 case QHttp::Reading: stateStr = "reading"; break; 00174 case QHttp::Connected: stateStr = "connected"; break; 00175 case QHttp::Closing: stateStr = "closing"; break; 00176 default: stateStr = "unknown state: "; break; 00177 } 00178 00179 LOG(VB_NETWORK, LOG_DEBUG, QString("HttpComms::stateChanged: %1 (%2)") 00180 .arg(stateStr) 00181 .arg(state)); 00182 } 00183 00184 void HttpComms::headerReceived(const QHttpResponseHeader &resp) 00185 { 00186 m_statusCode = resp.statusCode(); 00187 m_responseReason = resp.reasonPhrase(); 00188 00189 QString sidkey = "set-cookie"; 00190 00191 if (resp.hasKey(sidkey)) 00192 { 00193 QRegExp rx("PHPSESSID=(.+);"); 00194 rx.setMinimal(true); 00195 rx.setCaseSensitivity(Qt::CaseInsensitive); 00196 if (rx.indexIn(resp.value(sidkey)) >= 0) 00197 { 00198 m_cookie = "PHPSESSID=" + rx.cap(1); 00199 LOG(VB_NETWORK, LOG_DEBUG, 00200 QString("HttpComms found cookie: %1").arg(m_cookie)); 00201 } 00202 } 00203 00204 00205 LOG(VB_NETWORK, LOG_DEBUG, QString("Got HTTP response: %1:%2") 00206 .arg(m_statusCode) 00207 .arg(m_responseReason)); 00208 LOG(VB_NETWORK, LOG_DEBUG, QString("Keys: %1") 00209 .arg(resp.keys().join(",") )); 00210 00211 00212 if (resp.statusCode() >= 300 && resp.statusCode() <= 400) 00213 { 00214 // redirection 00215 QString uri = resp.value("LOCATION"); 00216 LOG(VB_NETWORK, LOG_DEBUG, QString("Redirection to: '%1'").arg(uri)); 00217 00218 m_redirectedURL = resp.value("LOCATION"); 00219 m_authNeeded = false; 00220 } 00221 else if ((resp.statusCode() == 401)) 00222 { 00223 // Toggle the state of our authentication pending flag 00224 // if we've gotten this after having tried to authenticate 00225 // once then we've failed authentication and turning the pending off will allow us to exit. 00226 m_authNeeded = !m_authNeeded; 00227 if (m_authNeeded) 00228 { 00229 QString authHeader(resp.value("www-authenticate")); 00230 00231 if (authHeader.startsWith("Digest") ) 00232 { 00233 if (!createDigestAuth(false, authHeader, &m_curRequest) ) 00234 { 00235 m_authNeeded = false; 00236 return; 00237 } 00238 } 00239 else 00240 { 00241 QString sUser(m_webCredentials.user + ':' + m_webCredentials.pass); 00242 QByteArray auth = QCodecs::base64Encode(sUser.toLocal8Bit()); 00243 m_curRequest.setValue( "Authorization", QString( "Basic " ).append( auth ) ); 00244 } 00245 00246 if (m_timer) 00247 { 00248 m_timer->stop(); 00249 m_timer->setSingleShot(true); 00250 m_timer->start(m_timeoutInterval); 00251 } 00252 00253 // Not sure if it's possible to receive a session ID or other cookie 00254 // before authenticating or not. 00255 if (!m_cookie.isEmpty()) 00256 { 00257 m_curRequest.setValue("Cookie", m_cookie); 00258 } 00259 00260 http->request(m_curRequest); 00261 } 00262 } 00263 else 00264 { 00265 m_authNeeded = false; 00266 } 00267 } 00268 00269 void HttpComms::timeout() 00270 { 00271 LOG(VB_GENERAL, LOG_ERR, QString("HttpComms::Timeout for url: %1") 00272 .arg(m_url.toString())); 00273 m_timeout = true; 00274 m_done = true; 00275 } 00276 00277 void HttpComms::dataReadProgress(int done, int total) 00278 { 00279 m_progress = done; 00280 m_total = total; 00281 } 00282 00283 00289 QString HttpComms::getHttp(QString &url, 00290 int timeoutMS, int maxRetries, 00291 int maxRedirects, bool allowGzip, 00292 Credentials *webCred, bool isInQtEventThread) 00293 { 00294 int redirectCount = 0; 00295 int timeoutCount = 0; 00296 QString res; 00297 HttpComms *httpGrabber = NULL; 00298 QString hostname; 00299 00300 while (1) 00301 { 00302 QUrl qurl(url); 00303 if (hostname.isEmpty()) 00304 hostname = qurl.host(); // hold onto original host 00305 if (qurl.host().isEmpty()) // can occur on redirects to partial paths 00306 qurl.setHost(hostname); 00307 00308 LOG(VB_NETWORK, LOG_DEBUG, 00309 QString("getHttp: grabbing: %1").arg(qurl.toString())); 00310 00311 delete httpGrabber; 00312 00313 httpGrabber = new HttpComms; 00314 00315 if (webCred) 00316 httpGrabber->setCredentials(*webCred, CRED_WEB); 00317 00318 httpGrabber->request(qurl, timeoutMS, allowGzip); 00319 00320 00321 while (!httpGrabber->isDone()) 00322 { 00323 if (isInQtEventThread) 00324 qApp->processEvents(); 00325 usleep(10000); 00326 } 00327 00328 // Handle timeout 00329 if (httpGrabber->isTimedout()) 00330 { 00331 LOG(VB_NETWORK, LOG_INFO, QString("timeout for url: %1").arg(url)); 00332 00333 // Increment the counter and check we're not over the limit 00334 if (timeoutCount++ >= maxRetries) 00335 { 00336 LOG(VB_GENERAL, LOG_ERR, 00337 QString("Failed to contact server for url: %1").arg(url)); 00338 break; 00339 } 00340 00341 // Try again 00342 LOG(VB_NETWORK, LOG_DEBUG, QString("Attempt # %1/%2 for url: %3") 00343 .arg(timeoutCount + 1) 00344 .arg(maxRetries) 00345 .arg(url)); 00346 00347 continue; 00348 } 00349 00350 // Check for redirection 00351 if (!httpGrabber->getRedirectedURL().isEmpty()) 00352 { 00353 LOG(VB_NETWORK, LOG_DEBUG, 00354 QString("Redirection: %1, count: %2, max: %3") 00355 .arg(httpGrabber->getRedirectedURL()) 00356 .arg(redirectCount) 00357 .arg(maxRedirects)); 00358 00359 // Increment the counter and check we're not over the limit 00360 if (redirectCount++ >= maxRedirects) 00361 { 00362 LOG(VB_GENERAL, LOG_ERR, 00363 QString("Maximum redirections reached for url: %1") 00364 .arg(url)); 00365 break; 00366 } 00367 00368 url = httpGrabber->getRedirectedURL(); 00369 00370 // Try again 00371 timeoutCount = 0; 00372 continue; 00373 } 00374 00375 res = httpGrabber->getData(); 00376 break; 00377 } 00378 00379 delete httpGrabber; 00380 00381 LOG(VB_NETWORK, LOG_DEBUG, QString("Got %1 bytes from url: '%2'") 00382 .arg(res.length()) 00383 .arg(url)); 00384 LOG(VB_NETWORK, LOG_DEBUG, res); 00385 00386 return res; 00387 } 00388 00389 // getHttpFile - static function for grabbing a file from a http url 00390 // this is a synchronous function, it will block according to the vars 00391 bool HttpComms::getHttpFile(const QString& filename, QString& url, int timeoutMS, 00392 int maxRetries, int maxRedirects, 00393 bool allowGzip, Credentials* webCred) 00394 { 00395 int redirectCount = 0; 00396 int timeoutCount = 0; 00397 QByteArray data(0); 00398 bool res = false; 00399 HttpComms *httpGrabber = NULL; 00400 QString hostname; 00401 00402 while (1) 00403 { 00404 QUrl qurl(url); 00405 if (hostname.isEmpty()) 00406 hostname = qurl.host(); // hold onto original host 00407 00408 if (qurl.host().isEmpty()) // can occur on redirects to partial paths 00409 qurl.setHost(hostname); 00410 00411 LOG(VB_NETWORK, LOG_DEBUG, QString("getHttp: grabbing: '%1'") 00412 .arg(qurl.toString())); 00413 00414 delete httpGrabber; 00415 00416 httpGrabber = new HttpComms; 00417 00418 if (webCred) 00419 httpGrabber->setCredentials(*webCred, CRED_WEB); 00420 00421 httpGrabber->request(qurl, timeoutMS, allowGzip); 00422 00423 while (!httpGrabber->isDone()) 00424 { 00425 qApp->processEvents(); 00426 usleep(10000); 00427 } 00428 00429 int statusCode = httpGrabber->getStatusCode(); 00430 if (statusCode < 200 || statusCode > 401) 00431 { 00432 LOG(VB_GENERAL, LOG_ERR, 00433 QString("Server returned an error status code %1 for url: %2") 00434 .arg(statusCode) 00435 .arg(url)); 00436 break; 00437 } 00438 00439 // Handle timeout 00440 if (httpGrabber->isTimedout()) 00441 { 00442 LOG(VB_NETWORK, LOG_DEBUG, QString("Timeout for url: '%1'") 00443 .arg(url)); 00444 00445 // Increment the counter and check we're not over the limit 00446 if (timeoutCount++ >= maxRetries) 00447 { 00448 LOG(VB_GENERAL, LOG_ERR, 00449 QString("Failed to contact server for url: '%1'") 00450 .arg(url)); 00451 break; 00452 } 00453 00454 // Try again 00455 LOG(VB_NETWORK, LOG_DEBUG, QString("Attempt # %1/%2 for url: %3") 00456 .arg(timeoutCount + 1) 00457 .arg(maxRetries) 00458 .arg(url)); 00459 00460 continue; 00461 } 00462 00463 // Check for redirection 00464 if (!httpGrabber->getRedirectedURL().isEmpty()) 00465 { 00466 LOG(VB_NETWORK, LOG_DEBUG, 00467 QString("redirection: '%1', count: %2, max: %3") 00468 .arg(httpGrabber->getRedirectedURL()) 00469 .arg(redirectCount) 00470 .arg(maxRedirects)); 00471 00472 // Increment the counter and check we're not over the limit 00473 if (redirectCount++ >= maxRedirects) 00474 { 00475 LOG(VB_GENERAL, LOG_ERR, 00476 QString("Maximum redirections reached for url: %1") 00477 .arg(url)); 00478 break; 00479 } 00480 00481 url = httpGrabber->getRedirectedURL(); 00482 00483 // Try again 00484 timeoutCount = 0; 00485 continue; 00486 } 00487 00488 data = httpGrabber->getRawData(); 00489 00490 if (data.size() > 0) 00491 { 00492 LOG(VB_NETWORK, LOG_DEBUG, 00493 QString("getHttpFile: saving to file: '%1'") .arg(filename)); 00494 00495 QFile file(filename); 00496 if (file.open( QIODevice::WriteOnly )) 00497 { 00498 QDataStream stream(& file); 00499 stream.writeRawData((const char*)(data), data.size() ); 00500 file.close(); 00501 res = true; 00502 LOG(VB_NETWORK, LOG_DEBUG, 00503 QString("getHttpFile: File saved OK")); 00504 } 00505 else 00506 LOG(VB_NETWORK, LOG_DEBUG, 00507 "getHttpFile: Failed to open file for writing"); 00508 } 00509 else 00510 LOG(VB_NETWORK, LOG_DEBUG, "getHttpFile: nothing to save to file!"); 00511 00512 break; 00513 } 00514 00515 LOG(VB_NETWORK, LOG_DEBUG, QString("Got %1 bytes from url: '%2'") 00516 .arg(data.size()) .arg(url)); 00517 00518 delete httpGrabber; 00519 00520 return res; 00521 } 00522 00528 QString HttpComms::postHttp( 00529 QUrl &url, 00530 QHttpRequestHeader *pAddlHdr, QIODevice *pData, 00531 int timeoutMS, int maxRetries, 00532 int maxRedirects, bool allowGzip, 00533 Credentials *webCred, bool isInQtEventThread, 00534 QString userAgent) 00535 { 00536 int redirectCount = 0; 00537 int timeoutCount = 0; 00538 QString res; 00539 HttpComms *httpGrabber = NULL; 00540 QString hostname; 00541 00542 QHttpRequestHeader header("POST", url.path() + url.encodedQuery()); 00543 00544 // Add main header values 00545 header.setValue("Host", url.host()); 00546 00547 if (userAgent.toLower() == "<default>") 00548 { 00549 userAgent = "Mozilla/9.876 (X11; U; Linux 2.2.12-20 i686, en) " 00550 "Gecko/25250101 Netscape/5.432b1"; 00551 } 00552 if (!userAgent.isEmpty()) 00553 header.setValue("User-Agent", userAgent); 00554 00555 if (allowGzip) 00556 header.setValue( "Accept-Encoding", "gzip"); 00557 00558 // Merge any Additional Headers passed by caller. 00559 00560 if (pAddlHdr) 00561 { 00562 QList< QPair< QString, QString > > values = pAddlHdr->values(); 00563 00564 for (QList< QPair< QString, QString > >::iterator it = values.begin(); 00565 it != values.end(); 00566 ++it ) 00567 { 00568 header.setValue( (*it).first, (*it).second ); 00569 } 00570 } 00571 00572 while (1) 00573 { 00574 if (hostname.isEmpty()) 00575 hostname = url.host(); // hold onto original host 00576 if (url.host().isEmpty()) // can occur on redirects to partial paths 00577 url.setHost(hostname); 00578 00579 LOG(VB_NETWORK, LOG_DEBUG, 00580 QString("postHttp: grabbing: %1").arg(url.toString())); 00581 00582 delete httpGrabber; 00583 00584 httpGrabber = new HttpComms; 00585 00586 if (webCred) 00587 httpGrabber->setCredentials(*webCred, CRED_WEB); 00588 00589 httpGrabber->request(url, header, timeoutMS, pData ); 00590 00591 while (!httpGrabber->isDone()) 00592 { 00593 if (isInQtEventThread) 00594 qApp->processEvents(); 00595 usleep(10000); 00596 } 00597 00598 // Handle timeout 00599 if (httpGrabber->isTimedout()) 00600 { 00601 LOG(VB_NETWORK, LOG_DEBUG, 00602 QString("timeout for url: %1").arg(url.toString())); 00603 00604 // Increment the counter and check we're not over the limit 00605 if (timeoutCount++ >= maxRetries) 00606 { 00607 LOG(VB_GENERAL, LOG_ERR, 00608 QString("Failed to contact server for url: %1") 00609 .arg(url.toString())); 00610 break; 00611 } 00612 00613 // Try again 00614 LOG(VB_NETWORK, LOG_DEBUG, QString("Attempt # %1/%2 for url: %3") 00615 .arg(timeoutCount + 1) 00616 .arg(maxRetries) 00617 .arg(url.toString())); 00618 00619 continue; 00620 } 00621 00622 // Check for redirection 00623 if (!httpGrabber->getRedirectedURL().isEmpty()) 00624 { 00625 LOG(VB_NETWORK, LOG_DEBUG, 00626 QString("Redirection: %1, count: %2, max: %3") 00627 .arg(httpGrabber->getRedirectedURL()) 00628 .arg(redirectCount) 00629 .arg(maxRedirects)); 00630 00631 // Increment the counter and check we're not over the limit 00632 if (redirectCount++ >= maxRedirects) 00633 { 00634 LOG(VB_GENERAL, LOG_ERR, 00635 QString("Maximum redirections reached for url: %1") 00636 .arg(url.toString())); 00637 break; 00638 } 00639 00640 url = QUrl( httpGrabber->getRedirectedURL() ); 00641 00642 // Try again 00643 timeoutCount = 0; 00644 continue; 00645 } 00646 00647 res = httpGrabber->getData(); 00648 break; 00649 } 00650 00651 delete httpGrabber; 00652 00653 LOG(VB_NETWORK, LOG_DEBUG, QString("Got %1 bytes from url: '%2'") 00654 .arg(res.length()) 00655 .arg(url.toString())); 00656 LOG(VB_NETWORK, LOG_DEBUG, res); 00657 00658 return res; 00659 } 00660 00661 00662 bool HttpComms::createDigestAuth ( bool isForProxy, const QString& authStr, QHttpRequestHeader* request) 00663 { 00664 const char *p; 00665 QString header; 00666 QString auth; 00667 QByteArray opaque; 00668 QByteArray Response; 00669 00670 DigestAuthInfo info; 00671 00672 opaque = ""; 00673 00674 if ( isForProxy ) 00675 { 00676 header = "Proxy-Authorization"; 00677 auth = "Digest "; 00678 info.username = qPrintable(m_proxyCredentials.user); 00679 info.password = qPrintable(m_proxyCredentials.pass); 00680 p = qPrintable(authStr); 00681 } 00682 else 00683 { 00684 header = "Authorization"; 00685 auth = "Digest "; 00686 info.username = qPrintable(m_webCredentials.user); 00687 info.password = qPrintable(m_webCredentials.pass); 00688 p = qPrintable(authStr); 00689 } 00690 00691 if (!p || !*p) 00692 return false; 00693 00694 p += 6; // Skip "Digest" 00695 00696 if ( info.username.isEmpty() || info.password.isEmpty() || !p ) 00697 return false; 00698 00699 00700 info.realm = ""; 00701 info.algorithm = "MD5"; 00702 info.nonce = ""; 00703 info.qop = ""; 00704 00705 // cnonce is recommended to contain about 64 bits of entropy 00706 // TODO: Fix this 00707 info.cnonce = "QPDExMTQ"; 00708 00709 // HACK: Should be fixed according to RFC 2617 section 3.2.2 00710 info.nc = "00000001"; 00711 00712 // Set the method used... 00713 info.method.clear(); 00714 info.method += request->method(); 00715 00716 // Parse the Digest response.... 00717 while (*p) 00718 { 00719 int i = 0; 00720 while ( (*p == ' ') || (*p == ',') || (*p == '\t')) {p++;} 00721 00722 if (strncasecmp(p, "realm=", 6 )==0) 00723 { 00724 p+=6; 00725 while ( *p == '"' ) p++; // Go past any number of " mark(s) first 00726 while ( p[i] != '"' ) i++; // Read everything until the last " mark 00727 info.realm = QByteArray( p, i+1 ); 00728 } 00729 else if (strncasecmp(p, "algorith=", 9)==0) 00730 { 00731 p+=9; 00732 while ( *p == '"' ) p++; // Go past any number of " mark(s) first 00733 while ( ( p[i] != '"' ) && ( p[i] != ',' ) && ( p[i] != '\0' ) ) i++; 00734 info.algorithm = QByteArray(p, i+1); 00735 } 00736 else if (strncasecmp(p, "algorithm=", 10)==0) 00737 { 00738 p+=10; 00739 while ( *p == '"' ) p++; // Go past any " mark(s) first 00740 while ( ( p[i] != '"' ) && ( p[i] != ',' ) && ( p[i] != '\0' ) ) i++; 00741 info.algorithm = QByteArray(p,i+1); 00742 } 00743 else if (strncasecmp(p, "domain=", 7)==0) 00744 { 00745 p+=7; 00746 while ( *p == '"' ) p++; // Go past any " mark(s) first 00747 while ( p[i] != '"' ) i++; // Read everything until the last " mark 00748 int pos; 00749 int idx = 0; 00750 QByteArray uri = QByteArray(p,i+1); 00751 do 00752 { 00753 pos = uri.indexOf( ' ', idx ); 00754 00755 if ( pos != -1 ) 00756 { 00757 QString sUrl = m_url.toString() + "//" + uri.mid(idx, pos-idx); 00758 QUrl u(sUrl); 00759 if (u.isValid ()) 00760 info.digestURI.append(qPrintable(u.toString())); 00761 } 00762 else 00763 { 00764 QString sUrl = m_url.toString() + "//" + uri.mid(idx, uri.length()-idx); 00765 QUrl u(sUrl); 00766 if (u.isValid ()) 00767 info.digestURI.append(qPrintable(u.toString())); 00768 } 00769 idx = pos+1; 00770 } while ( pos != -1 ); 00771 } 00772 else if (strncasecmp(p, "nonce=", 6)==0) 00773 { 00774 p+=6; 00775 while ( *p == '"' ) p++; // Go past any " mark(s) first 00776 while ( p[i] != '"' ) i++; // Read everything until the last " mark 00777 info.nonce = QByteArray(p,i+1); 00778 } 00779 else if (strncasecmp(p, "opaque=", 7)==0) 00780 { 00781 p+=7; 00782 while ( *p == '"' ) p++; // Go past any " mark(s) first 00783 while ( p[i] != '"' ) i++; // Read everything until the last " mark 00784 opaque = QByteArray(p,i+1); 00785 } 00786 else if (strncasecmp(p, "qop=", 4)==0) 00787 { 00788 p+=4; 00789 while ( *p == '"' ) p++; // Go past any " mark(s) first 00790 while ( p[i] != '"' ) i++; // Read everything until the last " mark 00791 info.qop = QByteArray(p,i+1); 00792 } 00793 p+=(i+1); 00794 } 00795 00796 if (info.realm.isEmpty() || info.nonce.isEmpty()) 00797 return false; 00798 00799 info.digestURI.append (m_url.path() + m_url.encodedQuery()); 00800 00801 #if 0 00802 LOG(VB_GENERAL, LOG_DEBUG, " RESULT OF PARSING:"); 00803 LOG(VB_GENERAL, LOG_DEBUG, QString(" algorithm: ") .arg(info.algorithm)); 00804 LOG(VB_GENERAL, LOG_DEBUG, QString(" realm: ") .arg(info.realm)); 00805 LOG(VB_GENERAL, LOG_DEBUG, QString(" nonce: ") .arg(info.nonce)); 00806 LOG(VB_GENERAL, LOG_DEBUG, QString(" opaque: ") .arg(opaque)); 00807 LOG(VB_GENERAL, LOG_DEBUG, QString(" qop: ") .arg(info.qop)); 00808 #endif 00809 00810 // Calculate the response... 00811 calculateDigestResponse( info, Response ); 00812 00813 auth += "username=\""; 00814 auth += info.username; 00815 00816 auth += "\", realm=\""; 00817 auth += info.realm; 00818 auth += "\""; 00819 00820 auth += ", nonce=\""; 00821 auth += info.nonce; 00822 00823 auth += "\", uri=\""; 00824 auth += m_url.path() + m_url.encodedQuery(); 00825 00826 auth += "\", algorithm=\""; 00827 auth += info.algorithm; 00828 auth +="\""; 00829 00830 if ( !info.qop.isEmpty() ) 00831 { 00832 auth += ", qop=\""; 00833 auth += info.qop; 00834 auth += "\", cnonce=\""; 00835 auth += info.cnonce; 00836 auth += "\", nc="; 00837 auth += info.nc; 00838 } 00839 00840 auth += ", response=\""; 00841 auth += Response; 00842 if ( !opaque.isEmpty() ) 00843 { 00844 auth += "\", opaque=\""; 00845 auth += opaque; 00846 } 00847 00848 auth += "\""; 00849 00850 LOG(VB_NETWORK, LOG_DEBUG, QString("Setting auth header %1 to '%2'") 00851 .arg(header).arg(auth)); 00852 00853 if (request) 00854 request->setValue(header, auth); 00855 00856 return true; 00857 } 00858 00859 00860 void HttpComms::calculateDigestResponse( DigestAuthInfo& info, QByteArray& Response ) 00861 { 00862 QMD5 md; 00863 QByteArray HA1; 00864 QByteArray HA2; 00865 00866 // Calculate H(A1) 00867 QByteArray authStr = info.username; 00868 authStr += ':'; 00869 authStr += info.realm; 00870 authStr += ':'; 00871 authStr += info.password; 00872 md.update( authStr ); 00873 00874 if (info.algorithm.toLower() == "md5-sess" ) 00875 { 00876 authStr = md.hexDigest(); 00877 authStr += ':'; 00878 authStr += info.nonce; 00879 authStr += ':'; 00880 authStr += info.cnonce; 00881 md.reset(); 00882 md.update( authStr ); 00883 } 00884 00885 HA1 = md.hexDigest(); 00886 00887 #if 0 00888 LOG(VB_GENERAL, LOG_DEBUG, QString(" calculateResponse(): A1 => %1") 00889 .arg(HA1)); 00890 #endif 00891 00892 QString sEncodedPathAndQuery = m_url.path() + m_url.encodedQuery(); 00893 00894 // Calculate H(A2) 00895 authStr = info.method; 00896 authStr += ':'; 00897 authStr += qPrintable(sEncodedPathAndQuery); 00898 00899 if ( info.qop == "auth-int" ) 00900 { 00901 authStr += ':'; 00902 authStr += info.entityBody; 00903 } 00904 00905 md.reset(); 00906 md.update( authStr ); 00907 HA2 = md.hexDigest(); 00908 00909 #if 0 00910 LOG(VB_GENERAL, LOG_DEBUG, QString(" calculateResponse(): A2 => %1") 00911 .arg(HA2)); 00912 #endif 00913 00914 // Calculate the response. 00915 authStr = HA1; 00916 authStr += ':'; 00917 authStr += info.nonce; 00918 authStr += ':'; 00919 if ( !info.qop.isEmpty() ) 00920 { 00921 authStr += info.nc; 00922 authStr += ':'; 00923 authStr += info.cnonce; 00924 authStr += ':'; 00925 authStr += info.qop; 00926 authStr += ':'; 00927 } 00928 00929 authStr += HA2; 00930 md.reset(); 00931 md.update( authStr ); 00932 Response = md.hexDigest(); 00933 00934 #if 0 00935 LOG(VB_GENERAL, LOG_DEBUG. QString(" calculateResponse(): Response => %1") 00936 .arg(Response)); 00937 #endif 00938 } 00939 00940
1.7.6.1