ResourceHandleBlackBerry.cpp   [plain text]


/*
 * Copyright (C) 2009, 2010 Research In Motion Limited. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "config.h"
#include "ResourceHandle.h"

#include "EventLoop.h"
#include "Frame.h"
#include "FrameLoaderClientBlackBerry.h"
#include "FrameNetworkingContextBlackBerry.h"
#include "NetworkManager.h"
#include "NotImplemented.h"
#include "Page.h"
#include "PageGroupLoadDeferrer.h"
#include "ResourceError.h"
#include "ResourceHandleClient.h"
#include "ResourceHandleInternal.h"
#include "ResourceRequest.h"
#include "ResourceResponse.h"
#include "SharedBuffer.h"
#include "ThreadableLoader.h" // for StoredCredentials

#include <network/FilterStream.h>

namespace WebCore {

class WebCoreSynchronousLoader : public ResourceHandleClient {
public:
    WebCoreSynchronousLoader();

    virtual void didReceiveResponse(ResourceHandle*, const ResourceResponse&);
    virtual void didReceiveData(ResourceHandle*, const char*, int, int);
    virtual void didFinishLoading(ResourceHandle*, double);
    virtual void didFail(ResourceHandle*, const ResourceError&);

    ResourceResponse resourceResponse() const { return m_response; }
    ResourceError resourceError() const { return m_error; }
    Vector<char> data() const { return m_data; }
    bool isDone() const { return m_isDone; }

private:
    ResourceResponse m_response;
    ResourceError m_error;
    Vector<char> m_data;
    bool m_isDone;
};

WebCoreSynchronousLoader::WebCoreSynchronousLoader()
    : m_isDone(false)
{
}

void WebCoreSynchronousLoader::didReceiveResponse(ResourceHandle*, const ResourceResponse& response)
{
    m_response = response;
}

void WebCoreSynchronousLoader::didReceiveData(ResourceHandle*, const char* data, int length, int)
{
    m_data.append(data, length);
}

void WebCoreSynchronousLoader::didFinishLoading(ResourceHandle*, double)
{
    m_isDone = true;
}

void WebCoreSynchronousLoader::didFail(ResourceHandle*, const ResourceError& error)
{
    m_error = error;
    m_isDone = true;
}

ResourceHandleInternal::~ResourceHandleInternal()
{
    notImplemented();
}

ResourceHandle::~ResourceHandle()
{
    notImplemented();
}

bool ResourceHandle::loadsBlocked()
{
    notImplemented();
    return false;
}

void ResourceHandle::platformSetDefersLoading(bool defersLoading)
{
    NetworkManager::instance()->setDefersLoading(this, defersLoading);
}

bool ResourceHandle::start(NetworkingContext* context)
{
    if (!context || !context->isValid())
        return false;

    // FIXME: clean up use of Frame now that we have NetworkingContext (see RIM Bug #1515)
    Frame* frame = static_cast<FrameNetworkingContextBlackBerry*>(context)->frame();
    if (!frame || !frame->loader() || !frame->loader()->client() || !client())
        return false;
    int playerId = static_cast<FrameLoaderClientBlackBerry*>(frame->loader()->client())->playerId();
    return NetworkManager::instance()->startJob(playerId, this, *frame, d->m_defersLoading);
}

void ResourceHandle::pauseLoad(bool pause)
{
    if (NetworkManager::instance())
        NetworkManager::instance()->pauseLoad(this, pause);
}

bool ResourceHandle::willLoadFromCache(ResourceRequest&, Frame*)
{
    notImplemented();
    return false;
}

void ResourceHandle::cancel()
{
    NetworkManager::instance()->stopJob(this);
}

void ResourceHandle::loadResourceSynchronously(NetworkingContext* context, const ResourceRequest& request, StoredCredentials, ResourceError& error, ResourceResponse& response, Vector<char>& data)
{
    if (!context || !context->isValid()) {
        ASSERT(false && "loadResourceSynchronously called with invalid networking context");
        return;
    }

    // FIXME: clean up use of Frame now that we have NetworkingContext (see RIM Bug #1515)
    Frame* frame = static_cast<FrameNetworkingContextBlackBerry*>(context)->frame();
    if (!frame || !frame->loader() || !frame->loader()->client() || !frame->page()) {
        ASSERT(false && "loadResourceSynchronously called without a frame or frame client");
        return;
    }

    PageGroupLoadDeferrer deferrer(frame->page(), true);
    TimerBase::fireTimersInNestedEventLoop();

    int playerId = static_cast<FrameLoaderClientBlackBerry*>(frame->loader()->client())->playerId();

    WebCoreSynchronousLoader syncLoader;

    bool defersLoading = false;
    bool shouldContentSniff = false;

    RefPtr<ResourceHandle> handle = adoptRef(new ResourceHandle(request, &syncLoader, defersLoading, shouldContentSniff));
    NetworkManager::instance()->startJob(playerId, handle, *frame, defersLoading);

    const double syncLoadTimeOut = 60; // seconds

    double startTime = currentTime();
    EventLoop loop;
    while (!syncLoader.isDone() && !loop.ended()) {
        loop.cycle();
        if (currentTime() - startTime > syncLoadTimeOut) {
            handle->cancel();
            error = ResourceError(ResourceError::platformErrorDomain, BlackBerry::Platform::FilterStream::StatusNetworkError, request.url().string(), "Time out");
            return;
        }
    }

    error = syncLoader.resourceError();
    data = syncLoader.data();
    response = syncLoader.resourceResponse();
}

} // namespace WebCore