1/*
2 * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
4 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1.  Redistributions of source code must retain the above copyright
11 *     notice, this list of conditions and the following disclaimer.
12 * 2.  Redistributions in binary form must reproduce the above copyright
13 *     notice, this list of conditions and the following disclaimer in the
14 *     documentation and/or other materials provided with the distribution.
15 * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
16 *     its contributors may be used to endorse or promote products derived
17 *     from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include "config.h"
32#include "ResourceLoadNotifier.h"
33
34#include "DocumentLoader.h"
35#include "Frame.h"
36#include "FrameLoader.h"
37#include "FrameLoaderClient.h"
38#include "InspectorInstrumentation.h"
39#include "Page.h"
40#include "ProgressTracker.h"
41#include "ResourceLoader.h"
42
43#if USE(QUICK_LOOK)
44#include "QuickLook.h"
45#endif
46
47namespace WebCore {
48
49ResourceLoadNotifier::ResourceLoadNotifier(Frame& frame)
50    : m_frame(frame)
51{
52}
53
54void ResourceLoadNotifier::didReceiveAuthenticationChallenge(ResourceLoader* loader, const AuthenticationChallenge& currentWebChallenge)
55{
56    didReceiveAuthenticationChallenge(loader->identifier(), loader->documentLoader(), currentWebChallenge);
57}
58
59void ResourceLoadNotifier::didReceiveAuthenticationChallenge(unsigned long identifier, DocumentLoader* loader, const AuthenticationChallenge& currentWebChallenge)
60{
61    m_frame.loader().client().dispatchDidReceiveAuthenticationChallenge(loader, identifier, currentWebChallenge);
62}
63
64void ResourceLoadNotifier::didCancelAuthenticationChallenge(ResourceLoader* loader, const AuthenticationChallenge& currentWebChallenge)
65{
66    didCancelAuthenticationChallenge(loader->identifier(), loader->documentLoader(), currentWebChallenge);
67}
68
69void ResourceLoadNotifier::didCancelAuthenticationChallenge(unsigned long identifier, DocumentLoader* loader, const AuthenticationChallenge& currentWebChallenge)
70{
71    m_frame.loader().client().dispatchDidCancelAuthenticationChallenge(loader, identifier, currentWebChallenge);
72}
73
74void ResourceLoadNotifier::willSendRequest(ResourceLoader* loader, ResourceRequest& clientRequest, const ResourceResponse& redirectResponse)
75{
76    m_frame.loader().applyUserAgent(clientRequest);
77
78    dispatchWillSendRequest(loader->documentLoader(), loader->identifier(), clientRequest, redirectResponse);
79}
80
81void ResourceLoadNotifier::didReceiveResponse(ResourceLoader* loader, const ResourceResponse& r)
82{
83    loader->documentLoader()->addResponse(r);
84
85    if (Page* page = m_frame.page())
86        page->progress().incrementProgress(loader->identifier(), r);
87
88    dispatchDidReceiveResponse(loader->documentLoader(), loader->identifier(), r, loader);
89}
90
91void ResourceLoadNotifier::didReceiveData(ResourceLoader* loader, const char* data, int dataLength, int encodedDataLength)
92{
93    if (Page* page = m_frame.page())
94        page->progress().incrementProgress(loader->identifier(), dataLength);
95
96    dispatchDidReceiveData(loader->documentLoader(), loader->identifier(), data, dataLength, encodedDataLength);
97}
98
99void ResourceLoadNotifier::didFinishLoad(ResourceLoader* loader, double finishTime)
100{
101    if (Page* page = m_frame.page())
102        page->progress().completeProgress(loader->identifier());
103    dispatchDidFinishLoading(loader->documentLoader(), loader->identifier(), finishTime);
104}
105
106void ResourceLoadNotifier::didFailToLoad(ResourceLoader* loader, const ResourceError& error)
107{
108    if (Page* page = m_frame.page())
109        page->progress().completeProgress(loader->identifier());
110
111    if (!error.isNull())
112        m_frame.loader().client().dispatchDidFailLoading(loader->documentLoader(), loader->identifier(), error);
113
114    InspectorInstrumentation::didFailLoading(&m_frame, loader->documentLoader(), loader->identifier(), error);
115}
116
117void ResourceLoadNotifier::assignIdentifierToInitialRequest(unsigned long identifier, DocumentLoader* loader, const ResourceRequest& request)
118{
119    m_frame.loader().client().assignIdentifierToInitialRequest(identifier, loader, request);
120}
121
122void ResourceLoadNotifier::dispatchWillSendRequest(DocumentLoader* loader, unsigned long identifier, ResourceRequest& request, const ResourceResponse& redirectResponse)
123{
124#if USE(QUICK_LOOK)
125    // Always allow QuickLook-generated URLs based on the protocol scheme.
126    if (!request.isNull() && request.url().protocolIs(QLPreviewProtocol()))
127        return;
128#endif
129
130    String oldRequestURL = request.url().string();
131    m_frame.loader().documentLoader()->didTellClientAboutLoad(request.url());
132
133    m_frame.loader().client().dispatchWillSendRequest(loader, identifier, request, redirectResponse);
134
135    // If the URL changed, then we want to put that new URL in the "did tell client" set too.
136    if (!request.isNull() && oldRequestURL != request.url().string())
137        m_frame.loader().documentLoader()->didTellClientAboutLoad(request.url());
138
139    InspectorInstrumentation::willSendRequest(&m_frame, identifier, loader, request, redirectResponse);
140
141    // Report WebTiming for all frames.
142    if (loader && !request.isNull() && request.url() == loader->requestURL())
143        request.setReportLoadTiming(true);
144
145#if ENABLE(RESOURCE_TIMING)
146    request.setReportLoadTiming(true);
147#endif
148}
149
150void ResourceLoadNotifier::dispatchDidReceiveResponse(DocumentLoader* loader, unsigned long identifier, const ResourceResponse& r, ResourceLoader* resourceLoader)
151{
152    InspectorInstrumentationCookie cookie = InspectorInstrumentation::willReceiveResourceResponse(&m_frame, identifier, r);
153    m_frame.loader().client().dispatchDidReceiveResponse(loader, identifier, r);
154    InspectorInstrumentation::didReceiveResourceResponse(cookie, identifier, loader, r, resourceLoader);
155}
156
157void ResourceLoadNotifier::dispatchDidReceiveData(DocumentLoader* loader, unsigned long identifier, const char* data, int dataLength, int encodedDataLength)
158{
159    m_frame.loader().client().dispatchDidReceiveContentLength(loader, identifier, dataLength);
160
161    InspectorInstrumentation::didReceiveData(&m_frame, identifier, data, dataLength, encodedDataLength);
162}
163
164void ResourceLoadNotifier::dispatchDidFinishLoading(DocumentLoader* loader, unsigned long identifier, double finishTime)
165{
166    m_frame.loader().client().dispatchDidFinishLoading(loader, identifier);
167
168    InspectorInstrumentation::didFinishLoading(&m_frame, loader, identifier, finishTime);
169}
170
171void ResourceLoadNotifier::dispatchDidFailLoading(DocumentLoader* loader, unsigned long identifier, const ResourceError& error)
172{
173    m_frame.loader().client().dispatchDidFailLoading(loader, identifier, error);
174
175    InspectorInstrumentation::didFailLoading(&m_frame, loader, identifier, error);
176}
177
178void ResourceLoadNotifier::sendRemainingDelegateMessages(DocumentLoader* loader, unsigned long identifier, const ResourceRequest& request, const ResourceResponse& response, const char* data, int dataLength, int encodedDataLength, const ResourceError& error)
179{
180    // If the request is null, willSendRequest cancelled the load. We should
181    // only dispatch didFailLoading in this case.
182    if (request.isNull()) {
183        ASSERT(error.isCancellation());
184        dispatchDidFailLoading(loader, identifier, error);
185        return;
186    }
187
188    if (!response.isNull())
189        dispatchDidReceiveResponse(loader, identifier, response);
190
191    if (dataLength > 0)
192        dispatchDidReceiveData(loader, identifier, data, dataLength, encodedDataLength);
193
194    if (error.isNull())
195        dispatchDidFinishLoading(loader, identifier, 0);
196    else
197        dispatchDidFailLoading(loader, identifier, error);
198}
199
200} // namespace WebCore
201