2 * Copyright (C) 2010 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 #include "core/loader/PingLoader.h"
35 #include "core/dom/Document.h"
36 #include "core/fetch/FetchContext.h"
37 #include "core/fetch/FetchInitiatorTypeNames.h"
38 #include "core/fetch/ResourceFetcher.h"
39 #include "core/fetch/UniqueIdentifier.h"
40 #include "core/frame/FrameConsole.h"
41 #include "core/frame/LocalFrame.h"
42 #include "core/inspector/InspectorInstrumentation.h"
43 #include "core/inspector/InspectorTraceEvents.h"
44 #include "core/loader/FrameLoader.h"
45 #include "core/loader/FrameLoaderClient.h"
46 #include "core/loader/MixedContentChecker.h"
47 #include "core/page/Page.h"
48 #include "platform/exported/WrappedResourceRequest.h"
49 #include "platform/network/ResourceError.h"
50 #include "platform/network/ResourceRequest.h"
51 #include "platform/network/ResourceResponse.h"
52 #include "platform/weborigin/SecurityOrigin.h"
53 #include "platform/weborigin/SecurityPolicy.h"
54 #include "public/platform/Platform.h"
55 #include "public/platform/WebURLLoader.h"
56 #include "public/platform/WebURLRequest.h"
57 #include "public/platform/WebURLResponse.h"
58 #include "wtf/OwnPtr.h"
62 static void finishPingRequestInitialization(ResourceRequest
& request
, LocalFrame
* frame
)
64 request
.setRequestContext(WebURLRequest::RequestContextPing
);
65 frame
->document()->fetcher()->context().addAdditionalRequestHeaders(request
, FetchSubresource
);
66 frame
->document()->fetcher()->context().setFirstPartyForCookies(request
);
69 void PingLoader::loadImage(LocalFrame
* frame
, const KURL
& url
)
71 if (!frame
->document()->securityOrigin()->canDisplay(url
)) {
72 FrameLoader::reportLocalLoadFailed(frame
, url
.string());
76 ResourceRequest
request(url
);
77 request
.setHTTPHeaderField("Cache-Control", "max-age=0");
78 finishPingRequestInitialization(request
, frame
);
80 FetchInitiatorInfo initiatorInfo
;
81 initiatorInfo
.name
= FetchInitiatorTypeNames::ping
;
82 PingLoader::start(frame
, request
, initiatorInfo
);
85 // http://www.whatwg.org/specs/web-apps/current-work/multipage/links.html#hyperlink-auditing
86 void PingLoader::sendLinkAuditPing(LocalFrame
* frame
, const KURL
& pingURL
, const KURL
& destinationURL
)
88 ResourceRequest
request(pingURL
);
89 request
.setHTTPMethod("POST");
90 request
.setHTTPContentType("text/ping");
91 request
.setHTTPBody(EncodedFormData::create("PING"));
92 request
.setHTTPHeaderField("Cache-Control", "max-age=0");
93 finishPingRequestInitialization(request
, frame
);
95 RefPtr
<SecurityOrigin
> pingOrigin
= SecurityOrigin::create(pingURL
);
96 // addAdditionalRequestHeaders() will have added a referrer for same origin requests,
97 // but the spec omits the referrer for same origin.
98 if (frame
->document()->securityOrigin()->isSameSchemeHostPort(pingOrigin
.get()))
99 request
.clearHTTPReferrer();
101 request
.setHTTPHeaderField("Ping-To", AtomicString(destinationURL
.string()));
103 // Ping-From follows the same rules as the default referrer beahavior for subresource requests.
104 // FIXME: Should Ping-From obey ReferrerPolicy?
105 if (!SecurityPolicy::shouldHideReferrer(pingURL
, frame
->document()->url().string()))
106 request
.setHTTPHeaderField("Ping-From", AtomicString(frame
->document()->url().string()));
108 FetchInitiatorInfo initiatorInfo
;
109 initiatorInfo
.name
= FetchInitiatorTypeNames::ping
;
110 PingLoader::start(frame
, request
, initiatorInfo
);
113 void PingLoader::sendViolationReport(LocalFrame
* frame
, const KURL
& reportURL
, PassRefPtr
<EncodedFormData
> report
, ViolationReportType type
)
115 ResourceRequest
request(reportURL
);
116 request
.setHTTPMethod("POST");
117 request
.setHTTPContentType(type
== ContentSecurityPolicyViolationReport
? "application/csp-report" : "application/json");
118 request
.setHTTPBody(report
);
119 finishPingRequestInitialization(request
, frame
);
121 FetchInitiatorInfo initiatorInfo
;
122 initiatorInfo
.name
= FetchInitiatorTypeNames::violationreport
;
123 PingLoader::start(frame
, request
, initiatorInfo
, SecurityOrigin::create(reportURL
)->isSameSchemeHostPort(frame
->document()->securityOrigin()) ? AllowStoredCredentials
: DoNotAllowStoredCredentials
);
126 void PingLoader::start(LocalFrame
* frame
, ResourceRequest
& request
, const FetchInitiatorInfo
& initiatorInfo
, StoredCredentials credentialsAllowed
)
128 if (MixedContentChecker::shouldBlockFetch(frame
, request
, request
.url()))
131 // Leak the ping loader, since it will kill itself as soon as it receives a response.
132 RefPtrWillBeRawPtr
<PingLoader
> loader
= adoptRefWillBeNoop(new PingLoader(frame
, request
, initiatorInfo
, credentialsAllowed
));
136 PingLoader::PingLoader(LocalFrame
* frame
, ResourceRequest
& request
, const FetchInitiatorInfo
& initiatorInfo
, StoredCredentials credentialsAllowed
)
137 : LocalFrameLifecycleObserver(frame
)
138 , m_timeout(this, &PingLoader::timeout
)
139 , m_url(request
.url())
140 , m_identifier(createUniqueIdentifier())
142 frame
->loader().client()->didDispatchPingLoader(request
.url());
144 TRACE_EVENT_INSTANT1("devtools.timeline", "ResourceSendRequest", TRACE_EVENT_SCOPE_THREAD
, "data", InspectorSendRequestEvent::data(m_identifier
, frame
, request
));
145 InspectorInstrumentation::willSendRequest(frame
, m_identifier
, frame
->loader().documentLoader(), request
, ResourceResponse(), initiatorInfo
);
147 m_loader
= adoptPtr(Platform::current()->createURLLoader());
149 WrappedResourceRequest
wrappedRequest(request
);
150 wrappedRequest
.setAllowStoredCredentials(credentialsAllowed
== AllowStoredCredentials
);
151 m_loader
->loadAsynchronously(wrappedRequest
, this);
153 // If the server never responds, FrameLoader won't be able to cancel this load and
154 // we'll sit here waiting forever. Set a very generous timeout, just in case.
155 m_timeout
.startOneShot(60000, FROM_HERE
);
158 PingLoader::~PingLoader()
164 void PingLoader::dispose()
173 void PingLoader::didReceiveResponse(WebURLLoader
*, const WebURLResponse
& response
)
175 if (LocalFrame
* frame
= this->frame()) {
176 TRACE_EVENT_INSTANT1("devtools.timeline", "ResourceFinish", TRACE_EVENT_SCOPE_THREAD
, "data", InspectorResourceFinishEvent::data(m_identifier
, 0, true));
177 const ResourceResponse
& resourceResponse
= response
.toResourceResponse();
178 InspectorInstrumentation::didReceiveResourceResponse(frame
, m_identifier
, 0, resourceResponse
, 0);
179 didFailLoading(frame
);
184 void PingLoader::didReceiveData(WebURLLoader
*, const char*, int, int)
186 if (LocalFrame
* frame
= this->frame()) {
187 TRACE_EVENT_INSTANT1("devtools.timeline", "ResourceFinish", TRACE_EVENT_SCOPE_THREAD
, "data", InspectorResourceFinishEvent::data(m_identifier
, 0, true));
188 didFailLoading(frame
);
193 void PingLoader::didFinishLoading(WebURLLoader
*, double, int64_t)
195 if (LocalFrame
* frame
= this->frame()) {
196 TRACE_EVENT_INSTANT1("devtools.timeline", "ResourceFinish", TRACE_EVENT_SCOPE_THREAD
, "data", InspectorResourceFinishEvent::data(m_identifier
, 0, true));
197 didFailLoading(frame
);
202 void PingLoader::didFail(WebURLLoader
*, const WebURLError
& resourceError
)
204 if (LocalFrame
* frame
= this->frame()) {
205 TRACE_EVENT_INSTANT1("devtools.timeline", "ResourceFinish", TRACE_EVENT_SCOPE_THREAD
, "data", InspectorResourceFinishEvent::data(m_identifier
, 0, true));
206 didFailLoading(frame
);
211 void PingLoader::timeout(Timer
<PingLoader
>*)
213 if (LocalFrame
* frame
= this->frame()) {
214 TRACE_EVENT_INSTANT1("devtools.timeline", "ResourceFinish", TRACE_EVENT_SCOPE_THREAD
, "data", InspectorResourceFinishEvent::data(m_identifier
, 0, true));
215 didFailLoading(frame
);
220 void PingLoader::didFailLoading(LocalFrame
* frame
)
222 InspectorInstrumentation::didFailLoading(frame
, m_identifier
, ResourceError::cancelledError(m_url
));
223 frame
->console().didFailLoading(m_identifier
, ResourceError::cancelledError(m_url
));
226 DEFINE_TRACE(PingLoader
)
228 LocalFrameLifecycleObserver::trace(visitor
);