1/*
2 * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
3 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
4 * Copyright (C) 2008 Holger Hans Peter Freyther
5 *
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
21 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
25 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include "config.h"
31#include "ResourceHandle.h"
32
33#include "CachedResourceLoader.h"
34#include "Frame.h"
35#include "FrameNetworkingContext.h"
36#include "NotImplemented.h"
37#include "Page.h"
38#include "QNetworkReplyHandler.h"
39#include "ResourceHandleClient.h"
40#include "ResourceHandleInternal.h"
41#include "SharedBuffer.h"
42
43#include <QAbstractNetworkCache>
44#include <QCoreApplication>
45#include <QNetworkAccessManager>
46#include <QNetworkReply>
47#include <QNetworkRequest>
48#include <QUrl>
49
50namespace WebCore {
51
52class WebCoreSynchronousLoader : public ResourceHandleClient {
53public:
54    WebCoreSynchronousLoader(ResourceError& error, ResourceResponse& response, Vector<char>& data)
55        : m_error(error)
56        , m_response(response)
57        , m_data(data)
58    {}
59
60    virtual void willSendRequest(ResourceHandle*, ResourceRequest&, const ResourceResponse&);
61    virtual void didReceiveResponse(ResourceHandle*, const ResourceResponse& response) { m_response = response; }
62    virtual void didReceiveData(ResourceHandle*, const char* data, int length, int) { m_data.append(data, length); }
63    virtual void didFinishLoading(ResourceHandle*, double /*finishTime*/) {}
64    virtual void didFail(ResourceHandle*, const ResourceError& error) { m_error = error; }
65private:
66    ResourceError& m_error;
67    ResourceResponse& m_response;
68    Vector<char>& m_data;
69};
70
71void WebCoreSynchronousLoader::willSendRequest(ResourceHandle* handle, ResourceRequest& request, const ResourceResponse& /*redirectResponse*/)
72{
73    // FIXME: This needs to be fixed to follow the redirect correctly even for cross-domain requests.
74    if (!protocolHostAndPortAreEqual(handle->firstRequest().url(), request.url())) {
75        ASSERT(m_error.isNull());
76        m_error.setIsCancellation(true);
77        request = ResourceRequest();
78        return;
79    }
80}
81
82ResourceHandleInternal::~ResourceHandleInternal()
83{
84}
85
86ResourceHandle::~ResourceHandle()
87{
88    if (d->m_job)
89        cancel();
90}
91
92bool ResourceHandle::start()
93{
94    // If NetworkingContext is invalid then we are no longer attached to a Page,
95    // this must be an attempted load from an unload event handler, so let's just block it.
96    if (d->m_context && !d->m_context->isValid())
97        return false;
98
99    if (!d->m_user.isEmpty() || !d->m_pass.isEmpty()) {
100        // If credentials were specified for this request, add them to the url,
101        // so that they will be passed to QNetworkRequest.
102        KURL urlWithCredentials(firstRequest().url());
103        urlWithCredentials.setUser(d->m_user);
104        urlWithCredentials.setPass(d->m_pass);
105        d->m_firstRequest.setURL(urlWithCredentials);
106    }
107
108    ResourceHandleInternal *d = getInternal();
109    d->m_job = new QNetworkReplyHandler(this, QNetworkReplyHandler::AsynchronousLoad, d->m_defersLoading);
110    return true;
111}
112
113void ResourceHandle::cancel()
114{
115    if (d->m_job) {
116        d->m_job->abort();
117        d->m_job = 0;
118    }
119}
120
121bool ResourceHandle::loadsBlocked()
122{
123    return false;
124}
125
126void ResourceHandle::platformLoadResourceSynchronously(NetworkingContext* context, const ResourceRequest& request, StoredCredentials /*storedCredentials*/, ResourceError& error, ResourceResponse& response, Vector<char>& data)
127{
128    WebCoreSynchronousLoader syncLoader(error, response, data);
129    RefPtr<ResourceHandle> handle = adoptRef(new ResourceHandle(context, request, &syncLoader, true, false));
130
131    ResourceHandleInternal* d = handle->getInternal();
132    if (!d->m_user.isEmpty() || !d->m_pass.isEmpty()) {
133        // If credentials were specified for this request, add them to the url,
134        // so that they will be passed to QNetworkRequest.
135        KURL urlWithCredentials(d->m_firstRequest.url());
136        urlWithCredentials.setUser(d->m_user);
137        urlWithCredentials.setPass(d->m_pass);
138        d->m_firstRequest.setURL(urlWithCredentials);
139    }
140
141    // starting in deferred mode gives d->m_job the chance of being set before sending the request.
142    d->m_job = new QNetworkReplyHandler(handle.get(), QNetworkReplyHandler::SynchronousLoad, true);
143    d->m_job->setLoadingDeferred(false);
144}
145
146void ResourceHandle::platformSetDefersLoading(bool defers)
147{
148    if (!d->m_job)
149        return;
150    d->m_job->setLoadingDeferred(defers);
151}
152
153} // namespace WebCore
154