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

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

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

Powered by Google App Engine
This is Rietveld 408576698