📄 qwebnetworkinterface.cpp
字号:
*/QWebNetworkManager::QWebNetworkManager() : QObject(0) , m_scheduledWork(false){ connect(this, SIGNAL(scheduleWork()), SLOT(doWork()), Qt::QueuedConnection);}QWebNetworkManager *QWebNetworkManager::self(){ // ensure everything's constructed and connected 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()) { // let's try to guess from the extension QString extension = job->d->request.url.path(); int index = extension.lastIndexOf(QLatin1Char('.')); if (index > 0) { extension = extension.mid(index + 1); contentType = MIMETypeRegistry::getMIMETypeForExtension(extension); } }// qDebug() << "Content-Type=" << contentType;// qDebug() << "Encoding=" << encoding; ResourceResponse response(url, contentType, 0 /* FIXME */, encoding, String() /* FIXME */); int statusCode = job->d->response.statusCode(); if (job->url().scheme() != QLatin1String("file")) response.setHTTPStatusCode(statusCode); else if (statusCode == 404) response.setHTTPStatusCode(statusCode); /* Fill in the other fields */ if (statusCode >= 300 && statusCode < 400) { // we're on a redirect page! if the 'Location:' field is valid, we redirect 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) { // this is standard-correct for 303 and practically-correct (no standard-correct) for 302 // also, it's required for Yahoo's login process for flickr.com which responds to a POST // with a 302 which must be GET'ed 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; // don't emit the "Document has moved here" type of HTML DEBUG() << "receivedData" << job->d->request.url.path(); if (client) client->didReceiveData(job->d->resourceHandle, data.constData(), data.length(), data.length() /*FixMe*/);}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) { //FIXME: error setting error was removed from ResourceHandle 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) { // #### fix custom ports 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(); //qDebug() << "handling data url:" << data; ASSERT(data.startsWith("data:")); // Here's the syntax of data URLs: // dataurl := "data:" [ mediatype ] [ ";base64" ] "," data // mediatype := [ type "/" subtype ] *( ";" parameter ) // data := *urlchar // parameter := attribute "=" value QByteArray header; bool base64 = false; int index = data.indexOf(','); if (index != -1) { header = data.mid(5, index - 5).toLower(); //qDebug() << "header=" << header; data = data.mid(index+1); //qDebug() << "data=" << data; if (header.endsWith(";base64")) { //qDebug() << "base64"; base64 = true; header = header.left(header.length() - 7); //qDebug() << "mime=" << header; } } 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(); }}/* * We will work on a copy of m_pendingWork. While dispatching m_pendingWork * new work will be added that will be handled at a later doWork call. doWork * will be called we set m_scheduledWork to false early in this method. */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) { // This job was not yet started if (static_cast<int>(work->job->status()) < QWebNetworkJob::JobStarted) continue; data(work->job, work->data); } else if (work->workType == JobWork::JobFinished) { // This job was not yet started... we have no idea if data comes by... // and it won't start in case of errors 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();}/*! \class QWebNetworkInterface The QWebNetworkInterface class provides an abstraction layer for WebKit's network interface. It allows to completely replace or extend the builtin network layer.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -