Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(13)

Side by Side Diff: third_party/WebKit/Source/core/loader/modulescript/ModuleScriptLoader.cpp

Issue 2697073002: [ES6 modules] Introduce ModuleScriptLoader (Closed)
Patch Set: rebased Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "core/loader/modulescript/ModuleScriptLoader.h"
6
7 #include "core/dom/Modulator.h"
8 #include "core/dom/ModuleScript.h"
9 #include "core/loader/modulescript/ModuleScriptLoaderClient.h"
10 #include "core/loader/modulescript/ModuleScriptLoaderRegistry.h"
11 #include "platform/loader/fetch/FetchUtils.h"
12 #include "platform/loader/fetch/ResourceFetcher.h"
13 #include "platform/loader/fetch/ResourceLoadingLog.h"
14 #include "platform/network/mime/MIMETypeRegistry.h"
15 #include "platform/weborigin/SecurityPolicy.h"
16 #include "wtf/text/AtomicString.h"
17
18 namespace blink {
19
20 ModuleScriptLoader::ModuleScriptLoader(Modulator* modulator,
21 ModuleScriptLoaderRegistry* registry,
22 ModuleScriptLoaderClient* client)
23 : m_modulator(modulator), m_registry(registry), m_client(client) {
24 DCHECK(modulator);
25 DCHECK(registry);
26 DCHECK(client);
27 }
28
29 ModuleScriptLoader::~ModuleScriptLoader() {}
30
31 #if DCHECK_IS_ON()
32 const char* ModuleScriptLoader::stateToString(ModuleScriptLoader::State state) {
33 switch (state) {
34 case State::Initial:
35 return "Initial";
36 case State::Fetching:
37 return "Fetching";
38 case State::Finished:
39 return "Finished";
40 }
41 NOTREACHED();
42 return "";
43 }
44 #endif
45
46 void ModuleScriptLoader::advanceState(ModuleScriptLoader::State newState) {
47 switch (m_state) {
48 case State::Initial:
49 DCHECK_EQ(newState, State::Fetching);
50 break;
51 case State::Fetching:
52 DCHECK_EQ(newState, State::Finished);
53 break;
54 case State::Finished:
55 NOTREACHED();
56 break;
57 }
58
59 #if DCHECK_IS_ON()
60 RESOURCE_LOADING_DVLOG(1)
61 << "ModuleLoader[" << m_url.getString() << "]::advanceState("
62 << stateToString(m_state) << " -> " << stateToString(newState) << ")";
63 #endif
64 m_state = newState;
65
66 if (m_state == State::Finished) {
67 m_registry->releaseFinishedLoader(this);
68 m_client->notifyNewSingleModuleFinished(m_moduleScript);
69 setResource(nullptr);
70 }
71 }
72
73 void ModuleScriptLoader::fetch(const ModuleScriptFetchRequest& moduleRequest,
74 ResourceFetcher* fetcher,
75 ModuleGraphLevel level) {
76 // https://html.spec.whatwg.org/#fetch-a-single-module-script
77
78 // Step 4. Set moduleMap[url] to "fetching".
79 advanceState(State::Fetching);
80
81 // Step 5. Let request be a new request whose url is url, ...
82 ResourceRequest resourceRequest(moduleRequest.url());
83 #if DCHECK_IS_ON()
84 m_url = moduleRequest.url();
85 #endif
86
87 // TODO(kouhei): handle "destination is destination,"
88
89 // ... type is "script", ...
90 // -> FetchResourceType is specified by ScriptResource::fetch
91
92 // parser metadata is parser state,
93 ResourceLoaderOptions options;
94 options.parserDisposition = moduleRequest.parserState();
95 // referrer is referrer,
96 if (!moduleRequest.referrer().isNull()) {
97 resourceRequest.setHTTPReferrer(SecurityPolicy::generateReferrer(
98 m_modulator->referrerPolicy(), moduleRequest.url(),
99 moduleRequest.referrer()));
100 }
101 // and client is fetch client settings object. -> set by ResourceFetcher
102
103 // As initiator for module script fetch is not specified in HTML spec,
104 // we specity "" as initiator per:
105 // https://fetch.spec.whatwg.org/#concept-request-initiator
106 const AtomicString& initiatorName = emptyAtom;
107
108 FetchRequest fetchRequest(resourceRequest, initiatorName, options);
109 // ... cryptographic nonce metadata is cryptographic nonce, ...
110 fetchRequest.setContentSecurityPolicyNonce(moduleRequest.nonce());
111 // Note: The fetch request's "origin" isn't specified in
112 // https://html.spec.whatwg.org/#fetch-a-single-module-script
113 // Thus, the "origin" is "client" per
114 // https://fetch.spec.whatwg.org/#concept-request-origin
115 // ... mode is "cors", ...
116 // ... credentials mode is credentials mode, ...
117 // TODO(tyoshino): FetchCredentialsMode should be used to communicate CORS
118 // mode.
119 CrossOriginAttributeValue crossOrigin =
120 moduleRequest.credentialsMode() ==
121 WebURLRequest::FetchCredentialsModeInclude
122 ? CrossOriginAttributeUseCredentials
123 : CrossOriginAttributeAnonymous;
124 fetchRequest.setCrossOriginAccessControl(m_modulator->securityOrigin(),
125 crossOrigin);
126
127 // Module scripts are always async.
128 fetchRequest.setDefer(FetchRequest::LazyLoad);
129
130 // Step 6. If the caller specified custom steps to perform the fetch,
131 // perform them on request, setting the is top-level flag if the top-level
132 // module fetch flag is set. Return from this algorithm, and when the custom
133 // perform the fetch steps complete with response response, run the remaining
134 // steps.
135 // Otherwise, fetch request. Return from this algorithm, and run the remaining
136 // steps as part of the fetch's process response for the response response.
137 // TODO(ServiceWorker team): Perform the "custom steps" for module usage
138 // inside service worker.
139 m_nonce = moduleRequest.nonce();
140 m_parserState = moduleRequest.parserState();
141
142 ScriptResource* resource = ScriptResource::fetch(fetchRequest, fetcher);
143 if (m_state == State::Finished) {
144 // ScriptResource::fetch() has succeeded synchronously,
145 // ::notifyFinished() already took care of the |resource|.
146 return;
147 }
148
149 if (!resource) {
150 // ScriptResource::fetch() has failed synchronously.
151 advanceState(State::Finished);
152 return;
153 }
154
155 // ScriptResource::fetch() is processed asynchronously.
156 setResource(resource);
157 }
158
159 bool ModuleScriptLoader::wasModuleLoadSuccessful(Resource* resource) {
160 // Implements conditions in Step 7 of
161 // https://html.spec.whatwg.org/#fetch-a-single-module-script
162
163 // - response's type is "error"
164 if (resource->errorOccurred()) {
165 return false;
166 }
167
168 const auto& response = resource->response();
169 // - response's status is not an ok status
170 if (response.isHTTP() && !FetchUtils::isOkStatus(response.httpStatusCode())) {
171 return false;
172 }
173
174 // The result of extracting a MIME type from response's header list
175 // (ignoring parameters) is not a JavaScript MIME type
176 // Note: For historical reasons, fetching a classic script does not include
177 // MIME type checking. In contrast, module scripts will fail to load if they
178 // are not of a correct MIME type.
179 // We use ResourceResponse::httpContentType() instead of mimeType(), as
180 // mimeType() may be rewritten by mime sniffer.
181 if (!MIMETypeRegistry::isSupportedJavaScriptMIMEType(
182 response.httpContentType()))
183 return false;
184
185 return true;
186 }
187
188 // ScriptResourceClient callback handler
189 void ModuleScriptLoader::notifyFinished(Resource*) {
190 // Note: "conditions" referred in Step 7 is implemented in
191 // wasModuleLoadSuccessful().
192 // Step 7. If any of the following conditions are met, set moduleMap[url] to
193 // null, asynchronously complete this algorithm with null, and abort these
194 // steps.
195 if (!wasModuleLoadSuccessful(resource())) {
196 advanceState(State::Finished);
197 return;
198 }
199
200 // Step 8. Let source text be the result of UTF-8 decoding response's body.
201 String sourceText = resource()->script();
202
203 // Step 9. Let module script be the result of creating a module script given
204 // source text, module map settings object, response's url, cryptographic
205 // nonce, parser state, and credentials mode.
206 m_moduleScript = createModuleScript(
207 sourceText, resource()->response().url(), m_modulator, m_nonce,
208 m_parserState, resource()->resourceRequest().fetchCredentialsMode());
209
210 advanceState(State::Finished);
211 }
212
213 // https://html.spec.whatwg.org/#creating-a-module-script
214 ModuleScript* ModuleScriptLoader::createModuleScript(
215 const String& sourceText,
216 const KURL& url,
217 Modulator* modulator,
218 const String& nonce,
219 ParserDisposition parserState,
220 WebURLRequest::FetchCredentialsMode credentialsMode) {
221 // Step 1. Let script be a new module script that this algorithm will
222 // subsequently initialize.
223 // Step 2. Set script's settings object to the environment settings object
224 // provided.
225 // Note: "script's settings object" will be "modulator".
226
227 // Delegate to Modulator::compileModule to process Steps 3-6.
228 ScriptModule result = modulator->compileModule(sourceText, url.getString());
229 // Step 6: "...return null, and abort these steps."
230 if (result.isNull())
231 return nullptr;
232 // Step 7. Set script's module record to result.
233 // Step 8. Set script's base URL to the script base URL provided.
234 // Step 9. Set script's cryptographic nonce to the cryptographic nonce
235 // provided.
236 // Step 10. Set script's parser state to the parser state.
237 // Step 11. Set script's credentials mode to the credentials mode provided.
238 // Step 12. Return script.
239 return ModuleScript::create(result, url, nonce, parserState, credentialsMode);
240 }
241
242 DEFINE_TRACE(ModuleScriptLoader) {
243 visitor->trace(m_modulator);
244 visitor->trace(m_moduleScript);
245 visitor->trace(m_registry);
246 visitor->trace(m_client);
247 ResourceOwner<ScriptResource>::trace(visitor);
248 }
249
250 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698