#include "config.h"
#include "loader.h"
#include "Cache.h"
#include "CachedImage.h"
#include "CachedResource.h"
#include "DocLoader.h"
#include "Frame.h"
#include "HTMLDocument.h"
#include "LoaderFunctions.h"
#include "Request.h"
#include "TransferJob.h"
#include "TransferJob.h"
#include <wtf/Assertions.h>
#include <wtf/Vector.h>
namespace WebCore {
static bool crossDomain(const DeprecatedString& a, const DeprecatedString& b)
{
if (a == b)
return false;
DeprecatedStringList l1 = DeprecatedStringList::split('.', a);
DeprecatedStringList l2 = DeprecatedStringList::split('.', b);
while (l1.count() > l2.count())
l1.pop_front();
while (l2.count() > l1.count())
l2.pop_front();
while (l2.count() >= 2) {
if (l1 == l2)
return false;
l1.pop_front();
l2.pop_front();
}
return true;
}
Loader::Loader()
{
m_requestsPending.setAutoDelete(true);
}
Loader::~Loader()
{
deleteAllValues(m_requestsLoading);
}
void Loader::load(DocLoader* dl, CachedResource* object, bool incremental)
{
Request* req = new Request(dl, object, incremental);
m_requestsPending.append(req);
servePendingRequests();
}
void Loader::servePendingRequests()
{
if (m_requestsPending.count() == 0)
return;
Request* req = m_requestsPending.take(0);
KURL u(req->cachedObject()->url().deprecatedString());
TransferJob* job = new TransferJob(this, "GET", u);
if (!req->cachedObject()->accept().isEmpty())
job->addMetaData("accept", req->cachedObject()->accept());
if (req->docLoader()) {
KURL r = req->docLoader()->doc()->URL();
if (r.protocol().startsWith("http") && r.path().isEmpty())
r.setPath("/");
job->addMetaData("referrer", r.url());
DeprecatedString domain = r.host();
if (req->docLoader()->doc()->isHTMLDocument())
domain = static_cast<HTMLDocument*>(req->docLoader()->doc())->domain().deprecatedString();
if (crossDomain(u.host(), domain))
job->addMetaData("cross-domain", "true");
}
if (job->start(req->docLoader()))
m_requestsLoading.add(job, req);
}
void Loader::receivedAllData(TransferJob* job, PlatformData allData)
{
RequestMap::iterator i = m_requestsLoading.find(job);
if (i == m_requestsLoading.end())
return;
Request* req = i->second;
m_requestsLoading.remove(i);
CachedResource* object = req->cachedObject();
DocLoader* docLoader = req->docLoader();
if (job->error() || job->isErrorPage()) {
docLoader->setLoadInProgress(true);
object->error();
docLoader->setLoadInProgress(false);
cache()->remove(object);
} else {
docLoader->setLoadInProgress(true);
object->data(req->buffer(), true);
#ifdef __APPLE__
object->setAllData(allData);
#endif
docLoader->setLoadInProgress(false);
object->finish();
}
delete req;
servePendingRequests();
}
void Loader::receivedResponse(TransferJob* job, PlatformResponse response)
{
#ifdef __APPLE__
Request* req = m_requestsLoading.get(job);
ASSERT(req);
ASSERT(response);
req->cachedObject()->setResponse(response);
req->cachedObject()->setExpireDate(CacheObjectExpiresTime(req->docLoader(), response), false);
DeprecatedString chs = job->queryMetaData("charset").deprecatedString();
if (!chs.isNull())
req->cachedObject()->setCharset(chs);
if (req->isMultipart()) {
ASSERT(req->cachedObject()->isImage());
static_cast<CachedImage*>(req->cachedObject())->clear();
if (req->docLoader()->frame())
req->docLoader()->frame()->checkCompleted();
} else if (ResponseIsMultipart(response)) {
req->setIsMultipart(true);
if (!req->cachedObject()->isImage())
job->cancel();
}
#endif
}
void Loader::receivedData(TransferJob* job, const char* data, int size)
{
Request* request = m_requestsLoading.get(job);
if (!request)
return;
CachedResource* object = request->cachedObject();
Vector<char>& buffer = object->bufferData(data, size, request);
if (request->isMultipart())
object->data(buffer, true);
else if (request->isIncremental())
object->data(buffer, false);
}
int Loader::numRequests(DocLoader* dl) const
{
int res = 0;
DeprecatedPtrListIterator<Request> pIt(m_requestsPending);
for (; pIt.current(); ++pIt) {
if (pIt.current()->docLoader() == dl)
res++;
}
RequestMap::const_iterator end = m_requestsLoading.end();
for (RequestMap::const_iterator i = m_requestsLoading.begin(); !(i == end); ++i) {
Request* r = i->second;
res += (r->docLoader() == dl && !r->isMultipart());
}
DeprecatedPtrListIterator<Request> bdIt(m_requestsBackgroundDecoding);
for (; bdIt.current(); ++bdIt)
if (bdIt.current()->docLoader() == dl)
res++;
if (dl->loadInProgress())
res++;
return res;
}
void Loader::cancelRequests(DocLoader* dl)
{
DeprecatedPtrListIterator<Request> pIt(m_requestsPending);
while (pIt.current()) {
if (pIt.current()->docLoader() == dl) {
cache()->remove(pIt.current()->cachedObject());
m_requestsPending.remove(pIt);
} else
++pIt;
}
Vector<TransferJob*, 256> jobsToCancel;
RequestMap::iterator end = m_requestsLoading.end();
for (RequestMap::iterator i = m_requestsLoading.begin(); i != end; ++i) {
Request* r = i->second;
if (r->docLoader() == dl)
jobsToCancel.append(i->first);
}
for (unsigned i = 0; i < jobsToCancel.size(); ++i) {
TransferJob* job = jobsToCancel[i];
Request* r = m_requestsLoading.get(job);
m_requestsLoading.remove(job);
cache()->remove(r->cachedObject());
job->kill();
}
DeprecatedPtrListIterator<Request> bdIt(m_requestsBackgroundDecoding);
while (bdIt.current()) {
if (bdIt.current()->docLoader() == dl) {
cache()->remove(bdIt.current()->cachedObject());
m_requestsBackgroundDecoding.remove(bdIt);
} else
++bdIt;
}
}
void Loader::removeBackgroundDecodingRequest(Request* r)
{
if (m_requestsBackgroundDecoding.containsRef(r))
m_requestsBackgroundDecoding.remove(r);
}
TransferJob* Loader::jobForRequest(const String& URL) const
{
RequestMap::const_iterator end = m_requestsLoading.end();
for (RequestMap::const_iterator i = m_requestsLoading.begin(); i != end; ++i) {
CachedResource* obj = i->second->cachedObject();
if (obj && obj->url() == URL)
return i->first;
}
return 0;
}
}