CSP: Update violation report 'Content-Type' header
[WebKit-https.git] / Source / WebCore / loader / PingLoader.cpp
1 /*
2  * Copyright (C) 2010 Google Inc. All rights reserved.
3  * Copyright (C) 2015 Roopesh Chander (roop@roopc.net)
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  *     * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *     * Redistributions in binary form must reproduce the above
12  * copyright notice, this list of conditions and the following disclaimer
13  * in the documentation and/or other materials provided with the
14  * distribution.
15  *     * Neither the name of Google Inc. nor the names of its
16  * contributors may be used to endorse or promote products derived from
17  * this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  *
31  */
32
33 #include "config.h"
34 #include "PingLoader.h"
35
36 #include "Document.h"
37 #include "FormData.h"
38 #include "Frame.h"
39 #include "FrameLoader.h"
40 #include "FrameLoaderClient.h"
41 #include "HTTPHeaderNames.h"
42 #include "InspectorInstrumentation.h"
43 #include "LoaderStrategy.h"
44 #include "Page.h"
45 #include "PlatformStrategies.h"
46 #include "ProgressTracker.h"
47 #include "ResourceHandle.h"
48 #include "ResourceLoadInfo.h"
49 #include "ResourceRequest.h"
50 #include "ResourceResponse.h"
51 #include "SecurityOrigin.h"
52 #include "SecurityPolicy.h"
53 #include "UserContentController.h"
54 #include <wtf/text/CString.h>
55
56 namespace WebCore {
57
58 #if ENABLE(CONTENT_EXTENSIONS)
59 static ContentExtensions::BlockedStatus processContentExtensionRulesForLoad(const Frame& frame, ResourceRequest& request, ResourceType resourceType)
60 {
61     if (DocumentLoader* documentLoader = frame.loader().documentLoader()) {
62         if (Page* page = frame.page()) {
63             if (UserContentController* controller = page->userContentController())
64                 return controller->processContentExtensionRulesForLoad(request, resourceType, *documentLoader);
65         }
66     }
67     return ContentExtensions::BlockedStatus::NotBlocked;
68 }
69 #endif
70
71 void PingLoader::loadImage(Frame& frame, const URL& url)
72 {
73     if (!frame.document()->securityOrigin()->canDisplay(url)) {
74         FrameLoader::reportLocalLoadFailed(&frame, url);
75         return;
76     }
77
78     ResourceRequest request(url);
79
80 #if ENABLE(CONTENT_EXTENSIONS)
81     if (processContentExtensionRulesForLoad(frame, request, ResourceType::Image) == ContentExtensions::BlockedStatus::Blocked)
82         return;
83 #endif
84
85     request.setHTTPHeaderField(HTTPHeaderName::CacheControl, "max-age=0");
86     String referrer = SecurityPolicy::generateReferrerHeader(frame.document()->referrerPolicy(), request.url(), frame.loader().outgoingReferrer());
87     if (!referrer.isEmpty())
88         request.setHTTPReferrer(referrer);
89     frame.loader().addExtraFieldsToSubresourceRequest(request);
90
91     startPingLoad(frame, request);
92 }
93
94 // http://www.whatwg.org/specs/web-apps/current-work/multipage/links.html#hyperlink-auditing
95 void PingLoader::sendPing(Frame& frame, const URL& pingURL, const URL& destinationURL)
96 {
97     ResourceRequest request(pingURL);
98     
99 #if ENABLE(CONTENT_EXTENSIONS)
100     if (processContentExtensionRulesForLoad(frame, request, ResourceType::Raw) == ContentExtensions::BlockedStatus::Blocked)
101         return;
102 #endif
103
104     request.setHTTPMethod("POST");
105     request.setHTTPContentType("text/ping");
106     request.setHTTPBody(FormData::create("PING"));
107     request.setHTTPHeaderField(HTTPHeaderName::CacheControl, "max-age=0");
108     frame.loader().addExtraFieldsToSubresourceRequest(request);
109
110     SecurityOrigin* sourceOrigin = frame.document()->securityOrigin();
111     Ref<SecurityOrigin> pingOrigin(SecurityOrigin::create(pingURL));
112     FrameLoader::addHTTPOriginIfNeeded(request, sourceOrigin->toString());
113     request.setHTTPHeaderField(HTTPHeaderName::PingTo, destinationURL);
114     if (!SecurityPolicy::shouldHideReferrer(pingURL, frame.loader().outgoingReferrer())) {
115         request.setHTTPHeaderField(HTTPHeaderName::PingFrom, frame.document()->url());
116         if (!sourceOrigin->isSameSchemeHostPort(&pingOrigin.get())) {
117             String referrer = SecurityPolicy::generateReferrerHeader(frame.document()->referrerPolicy(), pingURL, frame.loader().outgoingReferrer());
118             if (!referrer.isEmpty())
119                 request.setHTTPReferrer(referrer);
120         }
121     }
122
123     startPingLoad(frame, request);
124 }
125
126 void PingLoader::sendViolationReport(Frame& frame, const URL& reportURL, RefPtr<FormData>&& report, ViolationReportType reportType)
127 {
128     ResourceRequest request(reportURL);
129
130 #if ENABLE(CONTENT_EXTENSIONS)
131     if (processContentExtensionRulesForLoad(frame, request, ResourceType::Raw) == ContentExtensions::BlockedStatus::Blocked)
132         return;
133 #endif
134
135     request.setHTTPMethod(ASCIILiteral("POST"));
136     request.setHTTPBody(WTFMove(report));
137     switch (reportType) {
138     case ViolationReportType::ContentSecurityPolicy:
139         request.setHTTPContentType(ASCIILiteral("application/csp-report"));
140         break;
141     case ViolationReportType::XSSAuditor:
142         request.setHTTPContentType(ASCIILiteral("application/json"));
143         break;
144     }
145
146     bool removeCookies = true;
147     if (Document* document = frame.document()) {
148         if (SecurityOrigin* securityOrigin = document->securityOrigin()) {
149             if (securityOrigin->isSameSchemeHostPort(SecurityOrigin::create(reportURL).ptr()))
150                 removeCookies = false;
151         }
152     }
153     if (removeCookies)
154         request.setAllowCookies(false);
155
156     frame.loader().addExtraFieldsToSubresourceRequest(request);
157
158     String referrer = SecurityPolicy::generateReferrerHeader(frame.document()->referrerPolicy(), reportURL, frame.loader().outgoingReferrer());
159     if (!referrer.isEmpty())
160         request.setHTTPReferrer(referrer);
161
162     startPingLoad(frame, request);
163 }
164
165 void PingLoader::startPingLoad(Frame& frame, ResourceRequest& request)
166 {
167     unsigned long identifier = frame.page()->progress().createUniqueIdentifier();
168     // FIXME: Why activeDocumentLoader? I would have expected documentLoader().
169     // Itseems like the PingLoader should be associated with the current
170     // Document in the Frame, but the activeDocumentLoader will be associated
171     // with the provisional DocumentLoader if there is a provisional
172     // DocumentLoader.
173     bool shouldUseCredentialStorage = frame.loader().client().shouldUseCredentialStorage(frame.loader().activeDocumentLoader(), identifier);
174
175     InspectorInstrumentation::continueAfterPingLoader(frame, identifier, frame.loader().activeDocumentLoader(), request, ResourceResponse());
176
177     platformStrategies()->loaderStrategy()->createPingHandle(frame.loader().networkingContext(), request, shouldUseCredentialStorage);
178 }
179
180 }