1/*
2 * Copyright (C) 2009, 2010 Research In Motion Limited. All rights reserved.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17 */
18
19#include "config.h"
20#include "ResourceHandle.h"
21
22#include "EventLoop.h"
23#include "Frame.h"
24#include "FrameLoaderClientBlackBerry.h"
25#include "FrameNetworkingContextBlackBerry.h"
26#include "NetworkManager.h"
27#include "NotImplemented.h"
28#include "Page.h"
29#include "PageGroupLoadDeferrer.h"
30#include "ResourceError.h"
31#include "ResourceHandleClient.h"
32#include "ResourceHandleInternal.h"
33#include "ResourceRequest.h"
34#include "ResourceResponse.h"
35#include "SharedBuffer.h"
36#include "ThreadableLoader.h" // for StoredCredentials
37
38#include <network/FilterStream.h>
39
40namespace WebCore {
41
42class WebCoreSynchronousLoader : public ResourceHandleClient {
43public:
44    WebCoreSynchronousLoader();
45
46    virtual void didReceiveResponse(ResourceHandle*, const ResourceResponse&);
47    virtual void didReceiveData(ResourceHandle*, const char*, int, int);
48    virtual void didFinishLoading(ResourceHandle*, double);
49    virtual void didFail(ResourceHandle*, const ResourceError&);
50
51    ResourceResponse resourceResponse() const { return m_response; }
52    ResourceError resourceError() const { return m_error; }
53    Vector<char> data() const { return m_data; }
54    bool isDone() const { return m_isDone; }
55
56private:
57    ResourceResponse m_response;
58    ResourceError m_error;
59    Vector<char> m_data;
60    bool m_isDone;
61};
62
63WebCoreSynchronousLoader::WebCoreSynchronousLoader()
64    : m_isDone(false)
65{
66}
67
68void WebCoreSynchronousLoader::didReceiveResponse(ResourceHandle*, const ResourceResponse& response)
69{
70    m_response = response;
71}
72
73void WebCoreSynchronousLoader::didReceiveData(ResourceHandle*, const char* data, int length, int)
74{
75    m_data.append(data, length);
76}
77
78void WebCoreSynchronousLoader::didFinishLoading(ResourceHandle*, double)
79{
80    m_isDone = true;
81}
82
83void WebCoreSynchronousLoader::didFail(ResourceHandle*, const ResourceError& error)
84{
85    m_error = error;
86    m_isDone = true;
87}
88
89ResourceHandleInternal::~ResourceHandleInternal()
90{
91    notImplemented();
92}
93
94ResourceHandle::~ResourceHandle()
95{
96    notImplemented();
97}
98
99bool ResourceHandle::loadsBlocked()
100{
101    notImplemented();
102    return false;
103}
104
105void ResourceHandle::platformSetDefersLoading(bool defersLoading)
106{
107    NetworkManager::instance()->setDefersLoading(this, defersLoading);
108}
109
110bool ResourceHandle::start()
111{
112    if (!d->m_context || !d->m_context->isValid())
113        return false;
114
115    // FIXME: clean up use of Frame now that we have NetworkingContext (see RIM Bug #1515)
116    Frame* frame = static_cast<FrameNetworkingContextBlackBerry*>(d->m_context.get())->frame();
117    if (!frame || !frame->loader() || !frame->loader()->client() || !client())
118        return false;
119    int playerId = static_cast<FrameLoaderClientBlackBerry*>(frame->loader()->client())->playerId();
120    if (NetworkManager::instance()->startJob(playerId, this, frame, d->m_defersLoading) != BlackBerry::Platform::FilterStream::StatusSuccess)
121        scheduleFailure(InvalidURLFailure);
122    return true;
123}
124
125void ResourceHandle::pauseLoad(bool pause)
126{
127    if (NetworkManager::instance())
128        NetworkManager::instance()->pauseLoad(this, pause);
129}
130
131void ResourceHandle::cancel()
132{
133    NetworkManager::instance()->stopJob(this);
134    setClient(0);
135}
136
137void ResourceHandle::platformLoadResourceSynchronously(NetworkingContext* context, const ResourceRequest& request, StoredCredentials, ResourceError& error, ResourceResponse& response, Vector<char>& data)
138{
139    if (!context || !context->isValid()) {
140        ASSERT(false && "loadResourceSynchronously called with invalid networking context");
141        return;
142    }
143
144    // FIXME: clean up use of Frame now that we have NetworkingContext (see RIM Bug #1515)
145    Frame* frame = static_cast<FrameNetworkingContextBlackBerry*>(context)->frame();
146    if (!frame || !frame->loader() || !frame->loader()->client() || !frame->page()) {
147        ASSERT(false && "loadResourceSynchronously called without a frame or frame client");
148        return;
149    }
150
151    PageGroupLoadDeferrer deferrer(frame->page(), true);
152    TimerBase::fireTimersInNestedEventLoop();
153
154    int playerId = static_cast<FrameLoaderClientBlackBerry*>(frame->loader()->client())->playerId();
155
156    WebCoreSynchronousLoader syncLoader;
157
158    bool defersLoading = false;
159    bool shouldContentSniff = false;
160
161    RefPtr<ResourceHandle> handle = adoptRef(new ResourceHandle(context, request, &syncLoader, defersLoading, shouldContentSniff));
162    int status = NetworkManager::instance()->startJob(playerId, handle, frame, defersLoading);
163    if (status != BlackBerry::Platform::FilterStream::StatusSuccess) {
164        handle->cancel();
165        error = ResourceError(ResourceError::platformErrorDomain, status, request.url().string(), BlackBerry::Platform::String::emptyString());
166        return;
167    }
168
169    const double syncLoadTimeOut = 60; // seconds
170
171    double startTime = currentTime();
172    EventLoop loop;
173    while (!syncLoader.isDone() && !loop.ended()) {
174        loop.cycle();
175        if (currentTime() - startTime > syncLoadTimeOut) {
176            handle->cancel();
177            error = ResourceError(ResourceError::platformErrorDomain, BlackBerry::Platform::FilterStream::StatusNetworkError, request.url().string(), "Time out");
178            return;
179        }
180    }
181
182    error = syncLoader.resourceError();
183    data = syncLoader.data();
184    response = syncLoader.resourceResponse();
185}
186
187} // namespace WebCore
188