MythTV  0.26-pre
mythhttphandler.cpp
Go to the documentation of this file.
00001 // -*- Mode: c++ -*-
00002 // Copyright (c) 2008, Daniel Thor Kristjansson
00003 // Licensed under the GPL v2 or later, see COPYING for details
00004 
00005 // Qt headers
00006 #include <QHttp>
00007 
00008 // Myth headers
00009 #include "mythhttphandler.h"
00010 #include "mythhttppool.h"
00011 #include "mythlogging.h"
00012 
00013 #define LOC      QString("MythHttpHandler: ")
00014 
00015 const uint MythHttpHandler::kMaxRedirectCount = 32;
00016 
00017 MythHttpHandler::MythHttpHandler(MythHttpPool *pool) :
00018     m_pool(pool), m_qhttp(new QHttp())
00019 {
00020     connect(m_qhttp, SIGNAL(done(bool)),
00021             this,    SLOT(Done(bool)));
00022     connect(m_qhttp, SIGNAL(requestFinished(int,bool)),
00023             this,    SLOT(RequestFinished(int,bool)));
00024     connect(m_qhttp, SIGNAL(requestStarted(int)),
00025             this,    SLOT(RequestStarted(int)));
00026     connect(m_qhttp, SIGNAL(stateChanged(int)),
00027             this,    SLOT(StateChanged(int)));
00028     connect(m_qhttp, SIGNAL(responseHeaderReceived(const QHttpResponseHeader&)),
00029             this,    SLOT(ResponseHeaderReceived(const QHttpResponseHeader&)));
00030 }
00031 
00032 void MythHttpHandler::TeardownAll(void)
00033 {
00034     QMutexLocker locker(&m_lock);
00035 
00036     if (m_qhttp)
00037     {
00038         m_qhttp->abort();
00039         m_qhttp->disconnect();
00040         m_qhttp->deleteLater();
00041     }
00042     m_pool = NULL;
00043     m_qhttp = NULL;
00044 }
00045 
00046 bool MythHttpHandler::HasPendingRequests(void) const
00047 {
00048     QMutexLocker locker(&m_lock);
00049     return (m_qhttp->hasPendingRequests() ||
00050             m_qhttp->currentRequest().isValid() ||
00051             !m_urls.empty());
00052 }
00053 
00054 void MythHttpHandler::AddUrlRequest(const QUrl &url)
00055 {
00056     QMutexLocker locker(&m_lock);
00057 
00058     LOG(VB_NETWORK, LOG_DEBUG, LOC +
00059         QString("AddUrlRequest(%1)").arg(url.toString()));
00060 
00061     if (!m_qhttp->hasPendingRequests() && !m_qhttp->currentRequest().isValid())
00062         Get(url);
00063     else
00064         m_urls.push_back(url);
00065 }
00066 
00067 void MythHttpHandler::Get(const QUrl &url)
00068 {
00069     LOG(VB_NETWORK, LOG_DEBUG, LOC + QString("Get(%1)").arg(url.toString()));
00070 
00071     m_cur_url          = url;
00072     m_cur_status_id    = 0;
00073     m_cur_status_str   = QString::null;
00074     m_cur_redirect_cnt = 0;
00075 
00076     QHttp::ConnectionMode mode = 
00077         m_cur_url.scheme().toLower() == "https" ? QHttp::ConnectionModeHttps : 
00078                                                   QHttp::ConnectionModeHttp;
00079     m_qhttp->setHost(m_cur_url.host(), mode, 
00080                      m_cur_url.port() == -1 ? 0 : m_cur_url.port());
00081     
00082     if (!m_cur_url.userName().isEmpty())
00083         m_qhttp->setUser(m_cur_url.userName(), m_cur_url.password());
00084 
00085     QByteArray path = QUrl::toPercentEncoding(m_cur_url.path(), "!$&'()*+,;=:@/");
00086     if (path.isEmpty())
00087         path = "/";
00088     
00089     if (m_cur_url.hasQuery()) 
00090         path += "?" + m_cur_url.encodedQuery();  
00091 
00092     m_cur_get_id = m_qhttp->get(path);
00093 }
00094 
00095 void MythHttpHandler::RemoveUrlRequest(const QUrl &url)
00096 {
00097     QMutexLocker locker(&m_lock);
00098 
00099     UrlQueue urls = m_urls;
00100     m_urls.clear();
00101     while (!urls.empty())
00102     {
00103         QUrl item = urls.front();
00104         urls.pop_front();
00105         if (item != url)
00106             m_urls.push_back(item);
00107     }
00108 
00109     if (url == m_cur_url)
00110     {
00111         m_cur_url          = QUrl();
00112         m_cur_status_id    = 0;
00113         m_cur_status_str   = QString::null;
00114         m_cur_redirect_cnt = 0;
00115         m_cur_get_id       = 0;
00116         m_qhttp->abort();
00117     }
00118 }
00119 
00120 void MythHttpHandler::Done(bool error)
00121 {
00122     QMutexLocker locker(&m_lock);
00123 
00124     LOG(VB_NETWORK, LOG_DEBUG, LOC + QString("Done(%1) url: %2")
00125             .arg(error).arg(m_cur_url.toString()));
00126 
00127     if (m_pool)
00128         m_pool->Done(m_cur_url.host(), this);
00129 }
00130 
00131 void MythHttpHandler::ResponseHeaderReceived(const QHttpResponseHeader &resp)
00132 {
00133     QMutexLocker locker(&m_lock);
00134 
00135     LOG(VB_NETWORK, LOG_DEBUG, LOC +
00136         QString("ResponseHeaderReceived(%1,%2) url: %3")
00137             .arg(resp.statusCode()).arg(resp.reasonPhrase())
00138             .arg(m_cur_url.toString()));
00139     m_cur_status_id  = resp.statusCode();
00140     m_cur_status_str = resp.reasonPhrase();
00141 }
00142 
00143 static QString extract_url(const QString &text)
00144 {
00145     QString url = text;
00146     static QMutex lock;
00147     static QRegExp aTagExp("<a.*href.*=.*>", Qt::CaseInsensitive);
00148     static QRegExp httpEndExp("\"|\\s|\'");
00149 
00150     QMutexLocker locker(&lock);
00151 
00152     int a_tag = url.indexOf(aTagExp);
00153     if (a_tag >= 0)
00154     {
00155         url = url.mid(a_tag+1);
00156         url = url.left(url.indexOf(">"));
00157         url = url.mid(url.indexOf("href", Qt::CaseInsensitive) + 4);
00158         url = url.mid(url.indexOf("=") + 1);
00159         url = url.trimmed();
00160         if ((url.size()>=2) && url[0] == QChar('"'))
00161         {
00162             url = url.mid(1);
00163             if (url[url.length()-1] == QChar('"'))
00164                 url = url.left(url.length()-1);
00165         }
00166         if ((url.size()>=2) && url[0] == QChar('\''))
00167         {
00168             url = url.mid(1);
00169             if (url[url.length()-1] == QChar('\''))
00170                 url = url.left(url.length()-1);
00171         }
00172         return url;
00173     }
00174 
00175     int http = url.indexOf("http:");
00176     if (http >= 0)
00177     {
00178         url = url.mid(http);
00179         int end_http = url.indexOf(httpEndExp);
00180         url = url.left(end_http);
00181         return url;
00182     }
00183 
00184     return QString::null;
00185 }
00186 
00187 void MythHttpHandler::RequestFinished(int id, bool error)
00188 {
00189     QMutexLocker locker(&m_lock);
00190 
00191     LOG(VB_NETWORK, LOG_DEBUG, LOC + QString("RequestFinished(%1,%2) url: %3")
00192             .arg(id).arg(error).arg(m_cur_url.toString()));
00193     if (error && m_pool)
00194     {
00195         m_pool->Update(m_qhttp->error(), m_qhttp->errorString(),
00196                        m_cur_url,
00197                        m_cur_status_id, m_cur_status_str, QByteArray());
00198     }
00199     else if ((id == m_cur_get_id) && m_pool)
00200     {
00201         if ((307 == m_cur_status_id) || // temporary move..
00202             (303 == m_cur_status_id) || // move.. MUST use get
00203             (302 == m_cur_status_id) || // temporary move..
00204             (301 == m_cur_status_id))   // permanent move..
00205         {
00206             m_cur_status_id = 0;
00207             QString urlStr = extract_url(QString(m_qhttp->readAll()));
00208             if (!urlStr.isEmpty() && m_cur_redirect_cnt < kMaxRedirectCount)
00209             {
00210                 m_cur_redirect_cnt++;
00211                 QUrl url = QUrl(urlStr);
00212                 m_qhttp->setHost(url.host());
00213                 QString path = url.path().isEmpty() ? "/" : url.path();
00214                 m_cur_get_id = m_qhttp->get(path);
00215                 return;
00216             }
00217         }
00218 
00219         m_pool->Update(QHttp::NoError, QString::null,
00220                        m_cur_url,
00221                        m_cur_status_id, m_cur_status_str,
00222                        m_qhttp->readAll());
00223     }
00224     else
00225         return;
00226 
00227     if (!m_urls.empty())
00228     {
00229         Get(m_urls.front());
00230         m_urls.pop_front();
00231     }
00232 }
00233 
00234 void MythHttpHandler::RequestStarted(int id)
00235 {
00236     QMutexLocker locker(&m_lock);
00237 
00238     LOG(VB_NETWORK, LOG_DEBUG, LOC + QString("RequestStarted(%1) url: %2")
00239             .arg(id).arg(m_cur_url.toString()));
00240 }
00241 
00242 void MythHttpHandler::StateChanged(int state)
00243 {
00244     QMutexLocker locker(&m_lock);
00245 
00246     LOG(VB_NETWORK, LOG_DEBUG, LOC + QString("StateChanged(%1) url: %2")
00247             .arg(state).arg(m_cur_url.toString()));
00248 }
00249 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends