18e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project/*
28e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Copyright (C) 2006 Apple Computer, Inc.  All rights reserved.
38e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
48e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Redistribution and use in source and binary forms, with or without
58e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * modification, are permitted provided that the following conditions
68e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * are met:
78e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 1. Redistributions of source code must retain the above copyright
88e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *    notice, this list of conditions and the following disclaimer.
98e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 2. Redistributions in binary form must reproduce the above copyright
108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *    notice, this list of conditions and the following disclaimer in the
118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *    documentation and/or other materials provided with the distribution.
128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project */
258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "config.h"
278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "IconLoader.h"
288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "Document.h"
308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "Frame.h"
318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "FrameLoader.h"
328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "FrameLoaderClient.h"
338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "IconDatabase.h"
348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "Logging.h"
358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "ResourceHandle.h"
366b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner#include "ResourceLoadScheduler.h"
378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "ResourceResponse.h"
388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "ResourceRequest.h"
398f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian#include "SharedBuffer.h"
408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "SubresourceLoader.h"
41635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include <wtf/UnusedParam.h>
4268513a70bcd92384395513322f1b801e7bf9c729Steve Block#include <wtf/text/CString.h>
438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectusing namespace std;
458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectnamespace WebCore {
478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectIconLoader::IconLoader(Frame* frame)
498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    : m_frame(frame)
508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    , m_loadIsInProgress(false)
518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
54dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve BlockPassOwnPtr<IconLoader> IconLoader::create(Frame* frame)
558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
565ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen    return adoptPtr(new IconLoader(frame));
578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectIconLoader::~IconLoader()
608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid IconLoader::startLoading()
648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (m_resourceLoader)
668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Set flag so we can detect the case where the load completes before
698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // SubresourceLoader::create returns.
708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_loadIsInProgress = true;
718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
722fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    ResourceRequest resourceRequest(m_frame->loader()->iconURL());
732fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    resourceRequest.setPriority(ResourceLoadPriorityLow);
742fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
752fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    RefPtr<SubresourceLoader> loader = resourceLoadScheduler()->scheduleSubresourceLoad(m_frame, this, resourceRequest);
768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!loader)
778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        LOG_ERROR("Failed to start load for icon at url %s", m_frame->loader()->iconURL().string().ascii().data());
788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Store the handle so we can cancel the load if stopLoading is called later.
808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // But only do it if the load hasn't already completed.
818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (m_loadIsInProgress)
828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_resourceLoader = loader.release();
838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid IconLoader::stopLoading()
868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    clearLoadingState();
888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid IconLoader::didReceiveResponse(SubresourceLoader* resourceLoader, const ResourceResponse& response)
918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // If we got a status code indicating an invalid response, then lets
938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // ignore the data and not try to decode the error page as an icon.
948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int status = response.httpStatusCode();
958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    LOG(IconDatabase, "IconLoader::didReceiveResponse() - Loader %p, response %i", resourceLoader, status);
968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (status && (status < 200 || status > 299)) {
988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        ResourceHandle* handle = resourceLoader->handle();
99967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch        finishLoading(handle ? handle->firstRequest().url() : KURL(), 0);
1008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
1018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
103635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectvoid IconLoader::didReceiveData(SubresourceLoader* unusedLoader, const char*, int unusedSize)
1048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
105635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#if LOG_DISABLED
106635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    UNUSED_PARAM(unusedLoader);
107635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    UNUSED_PARAM(unusedSize);
108635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#endif
109635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    LOG(IconDatabase, "IconLoader::didReceiveData() - Loader %p, number of bytes %i", unusedLoader, unusedSize);
1108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid IconLoader::didFail(SubresourceLoader* resourceLoader, const ResourceError&)
1138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    LOG(IconDatabase, "IconLoader::didFail() - Loader %p", resourceLoader);
1158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Until <rdar://problem/5463392> is resolved and we can properly cancel SubresourceLoaders when they get an error response,
1178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // we need to be prepared to receive this call even after we've "finished loading" once.
1188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // After it is resolved, we can restore an assertion that the load is in progress if ::didFail() is called
1198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (m_loadIsInProgress) {
1218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        ASSERT(resourceLoader == m_resourceLoader);
1228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        ResourceHandle* handle = resourceLoader->handle();
123967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch        finishLoading(handle ? handle->firstRequest().url() : KURL(), 0);
1248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
1258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
127635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectvoid IconLoader::didReceiveAuthenticationChallenge(SubresourceLoader*, const AuthenticationChallenge&)
1288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // We don't ever want to prompt for authentication just for a site icon, so
1308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // implement this method to cancel the resource load
1318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_resourceLoader->cancel();
1328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
13481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdochvoid IconLoader::didFinishLoading(SubresourceLoader* resourceLoader, double)
1358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    LOG(IconDatabase, "IconLoader::didFinishLoading() - Loader %p", resourceLoader);
1378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Until <rdar://problem/5463392> is resolved and we can properly cancel SubresourceLoaders when they get an error response,
1398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // we need to be prepared to receive this call even after we've "finished loading" once.
1408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // After it is resolved, we can restore an assertion that the load is in progress if ::didFail() is called
1418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (m_loadIsInProgress) {
1438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        ASSERT(resourceLoader == m_resourceLoader);
1448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        ResourceHandle* handle = resourceLoader->handle();
145967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch        finishLoading(handle ? handle->firstRequest().url() : KURL(), m_resourceLoader->resourceData());
1468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
1478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid IconLoader::finishLoading(const KURL& iconURL, PassRefPtr<SharedBuffer> data)
1508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // When an icon load results in a 404 we commit it to the database here and clear the loading state.
1528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // But the SubresourceLoader continues pulling in data in the background for the 404 page if the server sends one.
1538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Once that data finishes loading or if the load is cancelled while that data is being read, finishLoading ends up being called a second time.
1548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // We need to change SubresourceLoader to have a mode where it will stop itself after receiving a 404 so this won't happen -
1558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // in the meantime, we'll only commit this data to the IconDatabase if it's the first time ::finishLoading() is called
1568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // <rdar://problem/5463392> tracks that enhancement
1578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!iconURL.isEmpty() && m_loadIsInProgress) {
1598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        LOG(IconDatabase, "IconLoader::finishLoading() - Committing iconURL %s to database", iconURL.string().ascii().data());
1608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_frame->loader()->commitIconURLToIconDatabase(iconURL);
161635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // Setting the icon data only after committing to the database ensures that the data is
162635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // kept in memory (so it does not have to be read from the database asynchronously), since
163635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // there is a page URL referencing it.
16481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        iconDatabase().setIconDataForIconURL(data, iconURL.string());
1658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_frame->loader()->client()->dispatchDidReceiveIcon();
1668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
1678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    clearLoadingState();
1698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid IconLoader::clearLoadingState()
1728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_resourceLoader = 0;
1748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_loadIsInProgress = false;
1758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
178