qwebnetworkinterface.cpp [plain text]
#include "config.h"
#include <qglobal.h>
#if QT_VERSION < 0x040400
#include "qwebframe.h"
#include "qwebnetworkinterface.h"
#include "qwebnetworkinterface_p.h"
#include "qwebpage.h"
#include "qcookiejar.h"
#include <qdebug.h>
#include <qfile.h>
#include <qnetworkproxy.h>
#include <qurl.h>
#include <QAuthenticator>
#include <QCoreApplication>
#include <QSslError>
#include "ResourceHandle.h"
#include "ResourceHandleClient.h"
#include "ResourceHandleInternal.h"
#include "MIMETypeRegistry.h"
#include "CookieJar.h"
#if 0
#define DEBUG qDebug
#else
#define DEBUG if (1) {} else qDebug
#endif
static QWebNetworkInterface *s_default_interface = 0;
static QWebNetworkManager *s_manager = 0;
using namespace WebCore;
uint qHash(const HostInfo &info)
{
return qHash(info.host) + info.port;
}
static bool operator==(const HostInfo &i1, const HostInfo &i2)
{
return i1.port == i2.port && i1.host == i2.host;
}
enum ParserState {
State_Begin,
State_FirstChar,
State_SecondChar
};
static QByteArray decodePercentEncoding(const QByteArray& input)
{
int actualLength = 0;
QByteArray tmpVal;
QByteArray output;
ParserState state = State_Begin;
output.resize(input.length());
tmpVal.resize(2);
for (int i = 0; i < input.length(); ++i)
if (state == State_Begin) {
if (input.at(i) == '%') {
state = State_FirstChar;
} else {
output[actualLength++] = input[i];
}
} else if (state == State_FirstChar) {
state = State_SecondChar;
tmpVal[0] = input[i];
} else if (state == State_SecondChar) {
state = State_Begin;
tmpVal[1] = input[i];
output[actualLength++] = tmpVal.toShort(0, 16);
}
output.resize(actualLength);
return output;
}
void QWebNetworkRequestPrivate::init(const WebCore::ResourceRequest &resourceRequest)
{
KURL url = resourceRequest.url();
QUrl qurl = QString(url.string());
init(resourceRequest.httpMethod(), qurl, &resourceRequest);
}
void QWebNetworkRequestPrivate::init(const QString &method, const QUrl &url, const WebCore::ResourceRequest *resourceRequest)
{
httpHeader = QHttpRequestHeader(method, url.toString(QUrl::RemoveScheme|QUrl::RemoveAuthority));
httpHeader.setValue(QLatin1String("Connection"), QLatin1String("Keep-Alive"));
setURL(url);
if (resourceRequest) {
httpHeader.setValue(QLatin1String("User-Agent"), resourceRequest->httpUserAgent());
const QString scheme = url.scheme().toLower();
if (scheme == QLatin1String("http") || scheme == QLatin1String("https")) {
QString cookies = QCookieJar::cookieJar()->cookies(resourceRequest->url());
if (!cookies.isEmpty())
httpHeader.setValue(QLatin1String("Cookie"), cookies);
}
const HTTPHeaderMap& loaderHeaders = resourceRequest->httpHeaderFields();
HTTPHeaderMap::const_iterator end = loaderHeaders.end();
for (HTTPHeaderMap::const_iterator it = loaderHeaders.begin(); it != end; ++it)
httpHeader.setValue(it->first, it->second);
if (method == "POST") {
Vector<char> data;
resourceRequest->httpBody()->flatten(data);
postData = QByteArray(data.data(), data.size());
httpHeader.setValue(QLatin1String("content-length"), QString::number(postData.size()));
}
}
}
void QWebNetworkRequestPrivate::setURL(const QUrl &u)
{
url = u;
int port = url.port();
const QString scheme = u.scheme();
if (port > 0 && (port != 80 || scheme != "http") && (port != 443 || scheme != "https"))
httpHeader.setValue(QLatin1String("Host"), url.host() + QLatin1Char(':') + QString::number(port));
else
httpHeader.setValue(QLatin1String("Host"), url.host());
}
QWebNetworkRequest::QWebNetworkRequest()
: d(new QWebNetworkRequestPrivate)
{
}
QWebNetworkRequest::QWebNetworkRequest(const QUrl &url, Method method, const QByteArray &postData)
: d(new QWebNetworkRequestPrivate)
{
d->init(method == Get ? "GET" : "POST", url);
d->postData = postData;
}
QWebNetworkRequest::QWebNetworkRequest(const QWebNetworkRequest &other)
: d(new QWebNetworkRequestPrivate(*other.d))
{
}
QWebNetworkRequest &QWebNetworkRequest::operator=(const QWebNetworkRequest &other)
{
*d = *other.d;
return *this;
}
QWebNetworkRequest::QWebNetworkRequest(const QWebNetworkRequestPrivate &priv)
: d(new QWebNetworkRequestPrivate(priv))
{
}
QWebNetworkRequest::QWebNetworkRequest(const WebCore::ResourceRequest &request)
: d(new QWebNetworkRequestPrivate)
{
d->init(request);
}
QWebNetworkRequest::~QWebNetworkRequest()
{
delete d;
}
QUrl QWebNetworkRequest::url() const
{
return d->url;
}
void QWebNetworkRequest::setUrl(const QUrl &url)
{
d->setURL(url);
}
QHttpRequestHeader QWebNetworkRequest::httpHeader() const
{
return d->httpHeader;
}
void QWebNetworkRequest::setHttpHeader(const QHttpRequestHeader &header) const
{
d->httpHeader = header;
}
QString QWebNetworkRequest::httpHeaderField(const QString &key) const
{
return d->httpHeader.value(key);
}
void QWebNetworkRequest::setHttpHeaderField(const QString &key, const QString &value)
{
d->httpHeader.setValue(key, value);
}
QByteArray QWebNetworkRequest::postData() const
{
return d->postData;
}
void QWebNetworkRequest::setPostData(const QByteArray &data)
{
d->postData = data;
}
QWebNetworkJob::QWebNetworkJob()
: d(new QWebNetworkJobPrivate)
{
}
QWebNetworkJob::~QWebNetworkJob()
{
delete d;
d = 0;
}
QUrl QWebNetworkJob::url() const
{
return d->request.url;
}
QByteArray QWebNetworkJob::postData() const
{
return d->request.postData;
}
QHttpRequestHeader QWebNetworkJob::httpHeader() const
{
return d->request.httpHeader;
}
QWebNetworkRequest QWebNetworkJob::request() const
{
return QWebNetworkRequest(d->request);
}
QHttpResponseHeader QWebNetworkJob::response() const
{
return d->response;
}
QString QWebNetworkJob::errorString() const
{
return d->errorString;
}
void QWebNetworkJob::setResponse(const QHttpResponseHeader &response)
{
d->response = response;
}
void QWebNetworkJob::setErrorString(const QString& errorString)
{
d->errorString = errorString;
}
bool QWebNetworkJob::cancelled() const
{
return !d->resourceHandle;
}
void QWebNetworkJob::ref()
{
++d->ref;
}
bool QWebNetworkJob::deref()
{
if (!--d->ref) {
delete this;
return false;
}
return true;
}
QWebNetworkInterface *QWebNetworkJob::networkInterface() const
{
return d->interface;
}
QWebFrame *QWebNetworkJob::frame() const
{
if (d->resourceHandle) {
ResourceHandleInternal *rhi = d->resourceHandle->getInternal();
if (rhi) {
return rhi->m_frame;
}
}
return 0;
}
QWebNetworkJob::JobStatus QWebNetworkJob::status() const
{
return d->jobStatus;
}
void QWebNetworkJob::setStatus(const JobStatus& status)
{
d->jobStatus = status;
}
QWebNetworkManager::QWebNetworkManager()
: QObject(0)
, m_scheduledWork(false)
{
connect(this, SIGNAL(scheduleWork()), SLOT(doWork()), Qt::QueuedConnection);
}
QWebNetworkManager *QWebNetworkManager::self()
{
QWebNetworkInterface::defaultInterface();
return s_manager;
}
bool QWebNetworkManager::add(ResourceHandle *handle, QWebNetworkInterface *interface, JobMode jobMode)
{
if (!interface)
interface = s_default_interface;
ASSERT(interface);
QWebNetworkJob *job = new QWebNetworkJob();
handle->getInternal()->m_job = job;
job->d->resourceHandle = handle;
job->d->interface = interface;
job->d->request.init(handle->request());
const QString method = handle->getInternal()->m_request.httpMethod();
if (method != "POST" && method != "GET" && method != "HEAD") {
qWarning("REQUEST: [%s]\n", qPrintable(job->d->request.httpHeader.toString()));
return false;
}
DEBUG() << "QWebNetworkManager::add:" << job->d->request.httpHeader.toString();
if (jobMode == SynchronousJob) {
Q_ASSERT(!m_synchronousJobs.contains(job));
m_synchronousJobs[job] = 1;
}
interface->addJob(job);
return true;
}
void QWebNetworkManager::cancel(ResourceHandle *handle)
{
QWebNetworkJob *job = handle->getInternal()->m_job;
if (!job)
return;
DEBUG() << "QWebNetworkManager::cancel:" << job->d->request.httpHeader.toString();
job->d->resourceHandle = 0;
job->d->interface->cancelJob(job);
handle->getInternal()->m_job = 0;
}
void QWebNetworkManager::started(QWebNetworkJob *job)
{
Q_ASSERT(job->d);
Q_ASSERT(job->status() == QWebNetworkJob::JobCreated ||
job->status() == QWebNetworkJob::JobRecreated);
job->setStatus(QWebNetworkJob::JobStarted);
ResourceHandleClient* client = 0;
if (job->d->resourceHandle) {
client = job->d->resourceHandle->client();
if (!client)
return;
} else {
return;
}
DEBUG() << "ResourceHandleManager::receivedResponse:";
DEBUG() << job->d->response.toString();
QStringList cookies = job->d->response.allValues("Set-Cookie");
KURL url(job->url());
foreach (QString c, cookies) {
QCookieJar::cookieJar()->setCookies(url, url, c);
}
QString contentType = job->d->response.value("Content-Type");
QString encoding;
int idx = contentType.indexOf(QLatin1Char(';'));
if (idx > 0) {
QString remainder = contentType.mid(idx + 1).toLower();
contentType = contentType.left(idx).trimmed();
idx = remainder.indexOf("charset");
if (idx >= 0) {
idx = remainder.indexOf(QLatin1Char('='), idx);
if (idx >= 0)
encoding = remainder.mid(idx + 1).trimmed();
}
}
if (contentType.isEmpty()) {
QString extension = job->d->request.url.path();
int index = extension.lastIndexOf(QLatin1Char('.'));
if (index > 0) {
extension = extension.mid(index + 1);
contentType = MIMETypeRegistry::getMIMETypeForExtension(extension);
}
}
ResourceResponse response(url, contentType,
0 ,
encoding,
String() );
int statusCode = job->d->response.statusCode();
if (job->url().scheme() != QLatin1String("file"))
response.setHTTPStatusCode(statusCode);
else if (statusCode == 404)
response.setHTTPStatusCode(statusCode);
if (statusCode >= 300 && statusCode < 400) {
QString location = job->d->response.value("location");
DEBUG() << "Redirection";
if (!location.isEmpty()) {
QUrl newUrl = job->d->request.url.resolved(location);
if (job->d->resourceHandle) {
ResourceRequest newRequest = job->d->resourceHandle->request();
newRequest.setURL(KURL(newUrl));
if (client)
client->willSendRequest(job->d->resourceHandle, newRequest, response);
}
QString method;
if (statusCode == 302 || statusCode == 303) {
method = "GET";
job->d->request.httpHeader.setContentLength(0);
} else {
method = job->d->request.httpHeader.method();
}
job->d->request.httpHeader.setRequest(method,
newUrl.toString(QUrl::RemoveScheme|QUrl::RemoveAuthority));
job->d->request.setURL(newUrl);
job->d->redirected = true;
return;
}
}
if (client)
client->didReceiveResponse(job->d->resourceHandle, response);
}
void QWebNetworkManager::data(QWebNetworkJob *job, const QByteArray &data)
{
Q_ASSERT(job->status() == QWebNetworkJob::JobStarted ||
job->status() == QWebNetworkJob::JobReceivingData);
job->setStatus(QWebNetworkJob::JobReceivingData);
ResourceHandleClient* client = 0;
if (job->d->resourceHandle) {
client = job->d->resourceHandle->client();
if (!client)
return;
} else {
return;
}
if (job->d->redirected)
return;
DEBUG() << "receivedData" << job->d->request.url.path();
if (client)
client->didReceiveData(job->d->resourceHandle, data.constData(), data.length(), data.length() );
}
void QWebNetworkManager::finished(QWebNetworkJob *job, int errorCode)
{
Q_ASSERT(errorCode == 1 ||
job->status() == QWebNetworkJob::JobStarted ||
job->status() == QWebNetworkJob::JobReceivingData);
if (m_synchronousJobs.contains(job))
m_synchronousJobs.remove(job);
job->setStatus(QWebNetworkJob::JobFinished);
ResourceHandleClient* client = 0;
if (job->d->resourceHandle) {
client = job->d->resourceHandle->client();
if (!client)
return;
} else {
job->deref();
return;
}
DEBUG() << "receivedFinished" << errorCode << job->url();
if (job->d->redirected) {
job->d->redirected = false;
job->setStatus(QWebNetworkJob::JobRecreated);
job->d->interface->addJob(job);
return;
}
if (job->d->resourceHandle)
job->d->resourceHandle->getInternal()->m_job = 0;
if (client) {
if (errorCode) {
client->didFail(job->d->resourceHandle,
ResourceError(job->d->request.url.host(), job->d->response.statusCode(),
job->d->request.url.toString(), job->d->errorString));
} else {
client->didFinishLoading(job->d->resourceHandle);
}
}
DEBUG() << "receivedFinished done" << job->d->request.url;
job->deref();
}
void QWebNetworkManager::addHttpJob(QWebNetworkJob *job)
{
HostInfo hostInfo(job->url());
WebCoreHttp *httpConnection = m_hostMapping.value(hostInfo);
if (!httpConnection) {
DEBUG() << " new connection to" << hostInfo.host << hostInfo.port;
httpConnection = new WebCoreHttp(this, hostInfo);
QObject::connect(httpConnection, SIGNAL(connectionClosed(const WebCore::HostInfo&)),
this, SLOT(httpConnectionClosed(const WebCore::HostInfo&)));
m_hostMapping[hostInfo] = httpConnection;
}
httpConnection->request(job);
}
void QWebNetworkManager::cancelHttpJob(QWebNetworkJob *job)
{
WebCoreHttp *httpConnection = m_hostMapping.value(job->url());
if (httpConnection)
httpConnection->cancel(job);
}
void QWebNetworkManager::httpConnectionClosed(const WebCore::HostInfo &info)
{
WebCoreHttp *connection = m_hostMapping.take(info);
connection->deleteLater();
}
void QWebNetworkInterfacePrivate::sendFileData(QWebNetworkJob* job, int statusCode, const QByteArray &data)
{
int error = statusCode >= 400 ? 1 : 0;
if (!job->cancelled()) {
QHttpResponseHeader response;
response.setStatusLine(statusCode);
response.setContentLength(data.length());
job->setResponse(response);
q->started(job);
if (!data.isEmpty())
q->data(job, data);
}
q->finished(job, error);
}
void QWebNetworkInterfacePrivate::parseDataUrl(QWebNetworkJob* job)
{
QByteArray data = job->url().toString().toLatin1();
ASSERT(data.startsWith("data:"));
QByteArray header;
bool base64 = false;
int index = data.indexOf(',');
if (index != -1) {
header = data.mid(5, index - 5).toLower();
data = data.mid(index+1);
if (header.endsWith(";base64")) {
base64 = true;
header = header.left(header.length() - 7);
}
} else {
data = QByteArray();
}
if (base64) {
data = QByteArray::fromBase64(data);
} else {
data = decodePercentEncoding(data);
}
if (header.isEmpty())
header = "text/plain;charset=US-ASCII";
int statusCode = 200;
QHttpResponseHeader response;
response.setContentType(header);
response.setContentLength(data.size());
job->setResponse(response);
int error = statusCode >= 400 ? 1 : 0;
q->started(job);
if (!data.isEmpty())
q->data(job, data);
q->finished(job, error);
}
void QWebNetworkManager::queueStart(QWebNetworkJob* job)
{
Q_ASSERT(job->d);
QMutexLocker locker(&m_queueMutex);
job->ref();
m_pendingWork.append(new JobWork(job));
doScheduleWork();
}
void QWebNetworkManager::queueData(QWebNetworkJob* job, const QByteArray& data)
{
ASSERT(job->d);
QMutexLocker locker(&m_queueMutex);
job->ref();
m_pendingWork.append(new JobWork(job, data));
doScheduleWork();
}
void QWebNetworkManager::queueFinished(QWebNetworkJob* job, int errorCode)
{
Q_ASSERT(job->d);
QMutexLocker locker(&m_queueMutex);
job->ref();
m_pendingWork.append(new JobWork(job, errorCode));
doScheduleWork();
}
void QWebNetworkManager::doScheduleWork()
{
if (!m_scheduledWork) {
m_scheduledWork = true;
emit scheduleWork();
}
}
void QWebNetworkManager::doWork()
{
m_queueMutex.lock();
m_scheduledWork = false;
bool hasSyncJobs = m_synchronousJobs.size();
const QHash<QWebNetworkJob*, int> syncJobs = m_synchronousJobs;
m_queueMutex.unlock();
foreach (JobWork* work, m_pendingWork) {
if (hasSyncJobs && !syncJobs.contains(work->job))
continue;
if (work->workType == JobWork::JobStarted)
started(work->job);
else if (work->workType == JobWork::JobData) {
if (static_cast<int>(work->job->status()) < QWebNetworkJob::JobStarted)
continue;
data(work->job, work->data);
} else if (work->workType == JobWork::JobFinished) {
if (static_cast<int>(work->job->status()) < QWebNetworkJob::JobStarted && work->errorCode != 1)
continue;
finished(work->job, work->errorCode);
}
m_queueMutex.lock();
m_pendingWork.removeAll(work);
m_queueMutex.unlock();
work->job->deref();
delete work;
}
m_queueMutex.lock();
if (hasSyncJobs && m_synchronousJobs.size() == 0)
doScheduleWork();
m_queueMutex.unlock();
}
static bool gRoutineAdded = false;
static void gCleanupInterface()
{
delete s_default_interface;
s_default_interface = 0;
}
void QWebNetworkInterface::setDefaultInterface(QWebNetworkInterface *defaultInterface)
{
if (s_default_interface == defaultInterface)
return;
if (s_default_interface)
delete s_default_interface;
s_default_interface = defaultInterface;
if (!gRoutineAdded) {
qAddPostRoutine(gCleanupInterface);
gRoutineAdded = true;
}
}
QWebNetworkInterface *QWebNetworkInterface::defaultInterface()
{
if (!s_default_interface) {
setDefaultInterface(new QWebNetworkInterface);
}
return s_default_interface;
}
QWebNetworkInterface::QWebNetworkInterface(QObject *parent)
: QObject(parent)
{
d = new QWebNetworkInterfacePrivate;
d->q = this;
if (!s_manager)
s_manager = new QWebNetworkManager;
}
QWebNetworkInterface::~QWebNetworkInterface()
{
delete d;
}
void QWebNetworkInterface::addJob(QWebNetworkJob *job)
{
QString protocol = job->url().scheme();
if (protocol == QLatin1String("http") || protocol == QLatin1String("https")) {
QWebNetworkManager::self()->addHttpJob(job);
return;
}
DEBUG() << "FileLoader::request" << job->url();
if (job->cancelled()) {
d->sendFileData(job, 400, QByteArray());
return;
}
QUrl url = job->url();
if (protocol == QLatin1String("data")) {
d->parseDataUrl(job);
return;
}
int statusCode = 200;
QByteArray data;
QString path = url.path();
if (protocol == QLatin1String("qrc")) {
protocol = "file";
path.prepend(QLatin1Char(':'));
}
if (!(protocol.isEmpty() || protocol == QLatin1String("file"))) {
statusCode = 404;
} else {
QFile f(path);
DEBUG() << "opening" << QString(url.path());
if (f.open(QIODevice::ReadOnly)) {
QHttpResponseHeader response;
response.setStatusLine(200);
job->setResponse(response);
data = f.readAll();
} else {
statusCode = 404;
}
}
if (statusCode == 404) {
QHttpResponseHeader response;
response.setStatusLine(404);
job->setResponse(response);
}
d->sendFileData(job, statusCode, data);
}
void QWebNetworkInterface::cancelJob(QWebNetworkJob *job)
{
QString protocol = job->url().scheme();
if (protocol == QLatin1String("http") || protocol == QLatin1String("https"))
QWebNetworkManager::self()->cancelHttpJob(job);
}
void QWebNetworkInterface::started(QWebNetworkJob* job)
{
Q_ASSERT(s_manager);
s_manager->queueStart(job);
}
void QWebNetworkInterface::data(QWebNetworkJob* job, const QByteArray& data)
{
Q_ASSERT(s_manager);
s_manager->queueData(job, data);
}
void QWebNetworkInterface::finished(QWebNetworkJob* job, int errorCode)
{
Q_ASSERT(s_manager);
s_manager->queueFinished(job, errorCode);
}
WebCoreHttp::WebCoreHttp(QObject* parent, const HostInfo &hi)
: QObject(parent), info(hi),
m_inCancel(false)
{
for (int i = 0; i < 2; ++i) {
connection[i].http = new QHttp(info.host, (hi.protocol == QLatin1String("https")) ? QHttp::ConnectionModeHttps : QHttp::ConnectionModeHttp, info.port);
connect(connection[i].http, SIGNAL(responseHeaderReceived(const QHttpResponseHeader&)),
this, SLOT(onResponseHeaderReceived(const QHttpResponseHeader&)));
connect(connection[i].http, SIGNAL(readyRead(const QHttpResponseHeader&)),
this, SLOT(onReadyRead()));
connect(connection[i].http, SIGNAL(requestFinished(int, bool)),
this, SLOT(onRequestFinished(int, bool)));
connect(connection[i].http, SIGNAL(done(bool)),
this, SLOT(onDone(bool)));
connect(connection[i].http, SIGNAL(stateChanged(int)),
this, SLOT(onStateChanged(int)));
connect(connection[i].http, SIGNAL(authenticationRequired(const QString&, quint16, QAuthenticator*)),
this, SLOT(onAuthenticationRequired(const QString&, quint16, QAuthenticator*)));
connect(connection[i].http, SIGNAL(proxyAuthenticationRequired(const QNetworkProxy&, QAuthenticator*)),
this, SLOT(onProxyAuthenticationRequired(const QNetworkProxy&, QAuthenticator*)));
connect(connection[i].http, SIGNAL(sslErrors(const QList<QSslError>&)),
this, SLOT(onSslErrors(const QList<QSslError>&)));
}
}
WebCoreHttp::~WebCoreHttp()
{
connection[0].http->deleteLater();
connection[1].http->deleteLater();
}
void WebCoreHttp::request(QWebNetworkJob *job)
{
m_pendingRequests.append(job);
scheduleNextRequest();
}
void WebCoreHttp::scheduleNextRequest()
{
int c = 0;
for (; c < 2; ++c) {
if (!connection[c].current)
break;
}
if (c >= 2)
return;
QWebNetworkJob *job = 0;
while (!job && !m_pendingRequests.isEmpty()) {
job = m_pendingRequests.takeFirst();
if (job->cancelled()) {
job->networkInterface()->finished(job, 1);
job = 0;
}
}
if (!job)
return;
QHttp *http = connection[c].http;
connection[c].current = job;
connection[c].id = -1;
#ifndef QT_NO_NETWORKPROXY
int proxyId = http->setProxy(job->frame()->page()->networkProxy());
#endif
QByteArray postData = job->postData();
if (!postData.isEmpty())
connection[c].id = http->request(job->httpHeader(), postData);
else
connection[c].id = http->request(job->httpHeader());
DEBUG() << "WebCoreHttp::scheduleNextRequest: using connection" << c;
DEBUG() << job->httpHeader().toString();
}
int WebCoreHttp::getConnection()
{
QObject *o = sender();
int c;
if (o == connection[0].http) {
c = 0;
} else {
Q_ASSERT(o == connection[1].http);
c = 1;
}
Q_ASSERT(connection[c].current);
return c;
}
void WebCoreHttp::onResponseHeaderReceived(const QHttpResponseHeader &resp)
{
QHttp *http = qobject_cast<QHttp*>(sender());
if (http->currentId() == 0) {
qDebug() << "ERROR! Invalid job id. Why?"; return;
}
int c = getConnection();
QWebNetworkJob *job = connection[c].current;
DEBUG() << "WebCoreHttp::slotResponseHeaderReceived connection=" << c;
DEBUG() << resp.toString();
job->setResponse(resp);
job->networkInterface()->started(job);
}
void WebCoreHttp::onReadyRead()
{
QHttp *http = qobject_cast<QHttp*>(sender());
if (http->currentId() == 0) {
qDebug() << "ERROR! Invalid job id. Why?"; return;
}
int c = getConnection();
QWebNetworkJob *job = connection[c].current;
Q_ASSERT(http == connection[c].http);
QByteArray data;
data.resize(http->bytesAvailable());
http->read(data.data(), data.length());
job->networkInterface()->data(job, data);
}
void WebCoreHttp::onRequestFinished(int id, bool error)
{
int c = getConnection();
if (connection[c].id != id) {
return;
}
QWebNetworkJob *job = connection[c].current;
if (!job) {
scheduleNextRequest();
return;
}
QHttp *http = connection[c].http;
DEBUG() << "WebCoreHttp::slotFinished connection=" << c << error << job;
if (error) {
DEBUG() << " error: " << http->errorString();
job->setErrorString(http->errorString());
}
if (!error && http->bytesAvailable()) {
QByteArray data;
data.resize(http->bytesAvailable());
http->read(data.data(), data.length());
job->networkInterface()->data(job, data);
}
job->networkInterface()->finished(job, error ? 1 : 0);
connection[c].current = 0;
connection[c].id = -1;
scheduleNextRequest();
}
void WebCoreHttp::onDone(bool error)
{
DEBUG() << "WebCoreHttp::onDone" << error;
}
void WebCoreHttp::onStateChanged(int state)
{
DEBUG() << "State changed to" << state << "and connections are" << connection[0].current << connection[1].current;
if (state == QHttp::Closing || state == QHttp::Unconnected) {
if (!m_inCancel && m_pendingRequests.isEmpty()
&& !connection[0].current && !connection[1].current)
emit connectionClosed(info);
}
}
void WebCoreHttp::cancel(QWebNetworkJob* request)
{
bool doEmit = true;
m_inCancel = true;
for (int i = 0; i < 2; ++i) {
if (request == connection[i].current) {
connection[i].http->abort();
doEmit = false;
}
}
if (!m_pendingRequests.removeAll(request))
doEmit = false;
m_inCancel = false;
if (doEmit)
request->networkInterface()->finished(request, 1);
if (m_pendingRequests.isEmpty()
&& !connection[0].current && !connection[1].current)
emit connectionClosed(info);
}
void WebCoreHttp::onSslErrors(const QList<QSslError>& errors)
{
int c = getConnection();
QWebNetworkJob *job = connection[c].current;
if (job) {
bool continueAnyway = false;
emit job->networkInterface()->sslErrors(job->frame(), job->url(), errors, &continueAnyway);
#ifndef QT_NO_OPENSSL
if (continueAnyway)
connection[c].http->ignoreSslErrors();
#endif
}
}
void WebCoreHttp::onAuthenticationRequired(const QString& hostname, quint16 port, QAuthenticator *auth)
{
int c = getConnection();
QWebNetworkJob *job = connection[c].current;
if (job) {
emit job->networkInterface()->authenticate(job->frame(), job->url(), hostname, port, auth);
if (auth->isNull())
connection[c].http->abort();
}
}
void WebCoreHttp::onProxyAuthenticationRequired(const QNetworkProxy& proxy, QAuthenticator *auth)
{
int c = getConnection();
QWebNetworkJob *job = connection[c].current;
if (job) {
emit job->networkInterface()->authenticateProxy(job->frame(), job->url(), proxy, auth);
if (auth->isNull())
connection[c].http->abort();
}
}
HostInfo::HostInfo(const QUrl& url)
: protocol(url.scheme())
, host(url.host())
, port(url.port())
{
if (port < 0) {
if (protocol == QLatin1String("http"))
port = 80;
else if (protocol == QLatin1String("https"))
port = 443;
}
}
#endif