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
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 )
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
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
00224
00225
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
00254
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();
00305 if (qurl.host().isEmpty())
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
00329 if (httpGrabber->isTimedout())
00330 {
00331 LOG(VB_NETWORK, LOG_INFO, QString("timeout for url: %1").arg(url));
00332
00333
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
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
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
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
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
00390
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();
00407
00408 if (qurl.host().isEmpty())
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
00440 if (httpGrabber->isTimedout())
00441 {
00442 LOG(VB_NETWORK, LOG_DEBUG, QString("Timeout for url: '%1'")
00443 .arg(url));
00444
00445
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
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
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
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
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
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
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();
00576 if (url.host().isEmpty())
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
00599 if (httpGrabber->isTimedout())
00600 {
00601 LOG(VB_NETWORK, LOG_DEBUG,
00602 QString("timeout for url: %1").arg(url.toString()));
00603
00604
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
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
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
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
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;
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
00706
00707 info.cnonce = "QPDExMTQ";
00708
00709
00710 info.nc = "00000001";
00711
00712
00713 info.method.clear();
00714 info.method += request->method();
00715
00716
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++;
00726 while ( p[i] != '"' ) i++;
00727 info.realm = QByteArray( p, i+1 );
00728 }
00729 else if (strncasecmp(p, "algorith=", 9)==0)
00730 {
00731 p+=9;
00732 while ( *p == '"' ) p++;
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++;
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++;
00747 while ( p[i] != '"' ) i++;
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++;
00776 while ( p[i] != '"' ) i++;
00777 info.nonce = QByteArray(p,i+1);
00778 }
00779 else if (strncasecmp(p, "opaque=", 7)==0)
00780 {
00781 p+=7;
00782 while ( *p == '"' ) p++;
00783 while ( p[i] != '"' ) i++;
00784 opaque = QByteArray(p,i+1);
00785 }
00786 else if (strncasecmp(p, "qop=", 4)==0)
00787 {
00788 p+=4;
00789 while ( *p == '"' ) p++;
00790 while ( p[i] != '"' ) i++;
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
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
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
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
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