blob: ddc0c709e62a051c0f677025fd639354fcbbea08 [file] [log] [blame]
youenn.fablet@crf.canon.frbba97932016-06-10 13:26:30 +00001/*
2 * Copyright (C) 2016 Canon Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
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
13 * distribution.
14 * * Neither the name of Canon 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.
17 *
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.
29 */
30
31#include "config.h"
32#include "CrossOriginPreflightChecker.h"
33
34#include "CachedRawResource.h"
35#include "CachedResourceLoader.h"
36#include "CachedResourceRequest.h"
37#include "ContentSecurityPolicy.h"
38#include "CrossOriginAccessControl.h"
39#include "CrossOriginPreflightResultCache.h"
40#include "DocumentThreadableLoader.h"
41#include "InspectorInstrumentation.h"
42#include "RuntimeEnabledFeatures.h"
43#include "ThreadableLoaderClient.h"
44
45namespace WebCore {
46
47CrossOriginPreflightChecker::CrossOriginPreflightChecker(DocumentThreadableLoader& loader, ResourceRequest&& request)
48 : m_loader(loader)
49 , m_request(WTFMove(request))
50{
51}
52
53CrossOriginPreflightChecker::~CrossOriginPreflightChecker()
54{
55 if (m_resource)
56 m_resource->removeClient(this);
57}
58
youenn.fablet@crf.canon.frbba97932016-06-10 13:26:30 +000059void CrossOriginPreflightChecker::validatePreflightResponse(DocumentThreadableLoader& loader, ResourceRequest&& request, unsigned long identifier, const ResourceResponse& response)
60{
61 Frame* frame = loader.document().frame();
62 ASSERT(frame);
63 auto cookie = InspectorInstrumentation::willReceiveResourceResponse(frame);
64 InspectorInstrumentation::didReceiveResourceResponse(cookie, identifier, frame->loader().documentLoader(), response, 0);
65
youenn.fablet@crf.canon.fr2959d282016-06-17 10:34:02 +000066 if (!response.isSuccessful()) {
67 loader.preflightFailure(identifier, ResourceError(errorDomainWebKitInternal, 0, request.url(), ASCIILiteral("Preflight response is not successful")));
68 return;
69 }
70
youenn.fablet@crf.canon.frbba97932016-06-10 13:26:30 +000071 String description;
72 if (!passesAccessControlCheck(response, loader.options().allowCredentials(), loader.securityOrigin(), description)) {
youenn.fablet@crf.canon.fr2959d282016-06-17 10:34:02 +000073 loader.preflightFailure(identifier, ResourceError(errorDomainWebKitInternal, 0, request.url(), description));
youenn.fablet@crf.canon.frbba97932016-06-10 13:26:30 +000074 return;
75 }
76
77 auto result = std::make_unique<CrossOriginPreflightResultCacheItem>(loader.options().allowCredentials());
78 if (!result->parse(response, description)
79 || !result->allowsCrossOriginMethod(request.httpMethod(), description)
80 || !result->allowsCrossOriginHeaders(request.httpHeaderFields(), description)) {
youenn.fablet@crf.canon.fr2959d282016-06-17 10:34:02 +000081 loader.preflightFailure(identifier, ResourceError(errorDomainWebKitInternal, 0, request.url(), description));
youenn.fablet@crf.canon.frbba97932016-06-10 13:26:30 +000082 return;
83 }
84
85 CrossOriginPreflightResultCache::singleton().appendEntry(loader.securityOrigin()->toString(), request.url(), WTFMove(result));
86 loader.preflightSuccess(WTFMove(request));
87}
88
89void CrossOriginPreflightChecker::notifyFinished(CachedResource* resource)
90{
91 ASSERT_UNUSED(resource, resource == m_resource);
92 if (m_resource->loadFailedOrCanceled()) {
commit-queue@webkit.orgf88d4fa2016-06-22 18:11:00 +000093 m_loader.preflightFailure(m_resource->identifier(), m_resource->resourceError());
youenn.fablet@crf.canon.frbba97932016-06-10 13:26:30 +000094 return;
95 }
96 validatePreflightResponse(m_loader, WTFMove(m_request), m_resource->identifier(), m_resource->response());
97}
98
99void CrossOriginPreflightChecker::startPreflight()
100{
101 auto options = m_loader.options();
102 options.setClientCredentialPolicy(DoNotAskClientForCrossOriginCredentials);
103 options.setSecurityCheck(DoSecurityCheck);
104 // Don't sniff content or send load callbacks for the preflight request.
105 options.setSendLoadCallbacks(DoNotSendCallbacks);
106 options.setSniffContent(DoNotSniffContent);
107 // Keep buffering the data for the preflight request.
108 options.setDataBufferingPolicy(BufferData);
109
youenn.fablet@crf.canon.fr2959d282016-06-17 10:34:02 +0000110 options.fetchOptions().redirect = FetchOptions::Redirect::Manual;
111
youenn.fablet@crf.canon.frbba97932016-06-10 13:26:30 +0000112 CachedResourceRequest preflightRequest(createAccessControlPreflightRequest(m_request, m_loader.securityOrigin()), options);
113 if (RuntimeEnabledFeatures::sharedFeatures().resourceTimingEnabled())
114 preflightRequest.setInitiator(m_loader.options().initiator);
115
116 ASSERT(!m_resource);
117 m_resource = m_loader.document().cachedResourceLoader().requestRawResource(preflightRequest);
118 if (m_resource)
119 m_resource->addClient(this);
120}
121
122void CrossOriginPreflightChecker::doPreflight(DocumentThreadableLoader& loader, ResourceRequest&& request)
123{
124 if (!loader.document().frame())
125 return;
126
127 ResourceRequest preflightRequest = createAccessControlPreflightRequest(request, loader.securityOrigin());
128 ResourceError error;
129 ResourceResponse response;
130 RefPtr<SharedBuffer> data;
131 unsigned identifier = loader.document().frame()->loader().loadResourceSynchronously(preflightRequest, loader.options().allowCredentials(), loader.options().clientCredentialPolicy(), error, response, data);
132
133 if (!error.isNull() && response.httpStatusCode() <= 0) {
commit-queue@webkit.orgf88d4fa2016-06-22 18:11:00 +0000134 loader.preflightFailure(identifier, error);
youenn.fablet@crf.canon.frbba97932016-06-10 13:26:30 +0000135 return;
136 }
137 validatePreflightResponse(loader, WTFMove(request), identifier, response);
138}
139
youenn.fablet@crf.canon.frbba97932016-06-10 13:26:30 +0000140void CrossOriginPreflightChecker::setDefersLoading(bool value)
141{
142 if (m_resource)
143 m_resource->setDefersLoading(value);
144}
145
146bool CrossOriginPreflightChecker::isXMLHttpRequest() const
147{
148 return m_loader.isXMLHttpRequest();
149}
150
151} // namespace WebCore