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

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

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

Powered by Google App Engine
This is Rietveld 408576698