00001
00002
00003
00004
00005
00006 #include <QHttp>
00007
00008
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) ||
00202 (303 == m_cur_status_id) ||
00203 (302 == m_cur_status_id) ||
00204 (301 == m_cur_status_id))
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