OLD | NEW |
---|---|
(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) { | |
hiroshige
2017/02/20 23:15:32
Why aren't stateToString() and m_url used in this
kouhei (in TOK)
2017/02/21 01:26:51
I used them in ::show(), which I accidentally drop
| |
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: | |
yhirano
2017/02/17 04:59:15
No default: is needed. Please add NOTRECHED() outs
kouhei (in TOK)
2017/02/21 01:26:51
Done.
| |
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: | |
hiroshige
2017/02/20 23:15:32
This |default| clause is also not needed.
kouhei (in TOK)
2017/02/21 01:26:51
Done.
| |
55 NOTREACHED(); | |
56 } | |
57 | |
58 m_state = newState; | |
59 | |
60 if (m_state == State::Finished) { | |
61 m_registry->releaseFinishedLoader(this); | |
62 m_client->notifyNewSingleModuleFinished(m_moduleScript); | |
63 } | |
64 } | |
65 | |
66 void ModuleScriptLoader::fetch(const ModuleScriptFetchRequest& moduleRequest, | |
hiroshige
2017/02/20 23:15:32
Could you add a comment with the link to the spec
kouhei (in TOK)
2017/02/21 01:26:51
Done.
| |
67 ResourceFetcher* fetcher, | |
68 ModuleGraphLevel level) { | |
69 // Step 4. Set moduleMap[url] to "fetching". | |
70 advanceState(State::Fetching); | |
71 | |
72 // Step 5. Let request be a new request whose url is url, ... | |
73 ResourceRequest resourceRequest(moduleRequest.url()); | |
74 #ifndef NDEBUG | |
75 m_url = moduleRequest.url(); | |
76 #endif | |
77 | |
78 // TODO(kouhei): handle "destination is destination," | |
79 // ... type is "script", -> FetchResourceType is specified by | |
80 // ScriptResource::fetch mode is "cors", ... | |
hiroshige
2017/02/20 23:15:32
Perhaps we need a line break or something between
kouhei (in TOK)
2017/02/21 01:26:51
Done.
| |
81 resourceRequest.setFetchRequestMode(WebURLRequest::FetchRequestModeCORS); | |
yhirano
2017/02/17 04:59:15
+tyoshino@:
You may need to call FetchRequest::se
kouhei (in TOK)
2017/02/21 01:26:51
Done, but I'm not confident here.
tyoshino (SeeGerritForStatus)
2017/02/21 03:47:17
Yes. setCrossOriginAccessControl() is needed.
Now
kouhei (in TOK)
2017/02/21 05:52:28
Done.
| |
82 // ... credentials mode is credentials mode, ... | |
83 resourceRequest.setFetchCredentialsMode(moduleRequest.credentialsMode()); | |
84 // parser metadata is parser state, | |
85 ResourceLoaderOptions options; | |
86 options.parserDisposition = moduleRequest.parserState(); | |
87 // referrer is referrer, | |
88 if (!moduleRequest.referrer().isNull()) { | |
89 resourceRequest.setHTTPReferrer(SecurityPolicy::generateReferrer( | |
90 m_modulator->referrerPolicy(), moduleRequest.url(), | |
91 moduleRequest.referrer())); | |
92 } | |
93 // and client is fetch client settings object. -> set by ResourceFetcher | |
94 | |
95 // TODO(kouhei): what initiatorName should we set here? should we set | |
hiroshige
2017/02/20 23:15:32
ScriptLoader sets the initiator to |m_element->loc
kouhei (in TOK)
2017/02/21 01:26:50
I'm not sure here too. If we are to align to the s
| |
96 // "module"? | |
97 // ... cryptographic nonce metadata is cryptographic nonce, ... | |
98 FetchRequest fetchRequest(resourceRequest, "module", options); | |
99 fetchRequest.setContentSecurityPolicyNonce(moduleRequest.nonce()); | |
100 | |
101 // Module scripts are always async. | |
102 fetchRequest.setDefer(FetchRequest::LazyLoad); | |
103 | |
104 // Step 6. If the caller specified custom steps to perform the fetch, | |
105 // perform them on request, setting the is top-level flag if the top-level | |
106 // module fetch flag is set. Return from this algorithm, and when the custom | |
107 // perform the fetch steps complete with response response, run the remaining | |
108 // steps. | |
109 // Otherwise, fetch request. Return from this algorithm, and run the remaining | |
110 // steps as part of the fetch's process response for the response response. | |
111 // TODO(ServiceWorker team): Perform the "custom steps" for module usage | |
112 // inside service worker. | |
113 (void)level; | |
114 // Otherwise, fetch request. Return from this algorithm, and run the remaining | |
hiroshige
2017/02/20 23:15:32
Lines 109-110 and 114-115 are duplicated.
kouhei (in TOK)
2017/02/21 01:26:50
Done.
| |
115 // steps as part of the fetch's process response for the response response. | |
116 // Note: response is always CORS-same-origin. | |
117 ScriptResource* resource = ScriptResource::fetch(fetchRequest, fetcher); | |
yhirano
2017/02/17 04:59:15
DCHECK(resource)?
kouhei (in TOK)
2017/02/21 01:26:51
Done.
hiroshige
2017/02/21 23:50:01
ScriptResource::fetch() can be return nullptr in g
kouhei (in TOK)
2017/02/22 03:52:29
You're right. We are only checking synchronous cas
yhirano
2017/02/22 08:02:57
I'm not following. It sounds we need to care about
kouhei (in TOK)
2017/02/23 03:49:26
Added test for this case/
| |
118 setResource(resource); | |
hiroshige
2017/02/20 23:15:32
notifyFinished() might be called synchronously her
kouhei (in TOK)
2017/02/21 01:26:50
I think this is fine for the current ModuleScriptL
hiroshige
2017/02/21 23:50:01
Hmm, then we have to set |m_nonce| and |m_parserSt
kouhei (in TOK)
2017/02/22 03:52:29
Done.
yhirano
2017/02/22 08:02:57
In such a case, I think we should not run |setReso
kouhei (in TOK)
2017/02/23 03:49:26
Done.
| |
119 | |
120 m_nonce = moduleRequest.nonce(); | |
121 m_parserState = moduleRequest.parserState(); | |
122 m_credentialsMode = moduleRequest.credentialsMode(); | |
123 } | |
124 | |
125 bool ModuleScriptLoader::wasModuleLoadSuccessful(Resource* resource) { | |
126 // Implements conditions in Step 7 of | |
127 // https://html.spec.whatwg.org/#fetch-a-single-module-script | |
128 | |
129 // - response's type is "error" | |
130 if (resource->errorOccurred()) { | |
131 return false; | |
132 } | |
133 | |
134 const auto& response = resource->response(); | |
135 // - response's status is not an ok status | |
136 if (response.isHTTP() && | |
137 (response.httpStatusCode() < 200 || response.httpStatusCode() >= 300)) { | |
138 return false; | |
139 } | |
140 | |
141 // The result of extracting a MIME type from response's header list | |
142 // (ignoring parameters) is not a JavaScript MIME type | |
143 // Note: For historical reasons, fetching a classic script does not include | |
144 // MIME type checking. In contrast, module scripts will fail to load if they | |
hiroshige
2017/02/20 23:15:32
Could you clarify that this refers to "response's"
kouhei (in TOK)
2017/02/21 01:26:51
This is a copy of spec text per https://html.spec.
hiroshige
2017/02/21 23:50:01
Acknowledged.
| |
145 // are not of a correct MIME type. | |
146 if (!MIMETypeRegistry::isSupportedJavaScriptMIMEType(response.mimeType())) | |
147 return false; | |
148 | |
149 return true; | |
150 } | |
151 | |
152 // ScriptResourceClient callback handler | |
153 void ModuleScriptLoader::notifyFinished(Resource*) { | |
154 // Note: "conditions" referred in Step 7 is implemented in | |
155 // wasModuleLoadSuccessful(). | |
156 // Step 7. If any of the following conditions are met, set moduleMap[url] to | |
157 // null, asynchronously complete this algorithm with null, and abort these | |
158 // steps. | |
159 if (!wasModuleLoadSuccessful(resource())) { | |
160 advanceState(State::Finished); | |
161 setResource(nullptr); | |
yhirano
2017/02/17 04:59:15
Is it preferable to move this statement into advan
kouhei (in TOK)
2017/02/21 01:26:50
Done.
| |
162 return; | |
163 } | |
164 | |
165 // Step 8. Let source text be the result of UTF-8 decoding response's body. | |
166 String sourceText = resource()->script(); | |
167 | |
168 // Step 9. Let module script be the result of creating a module script given | |
169 // source text, module map settings object, response's url, cryptographic | |
170 // nonce, parser state, and credentials mode. | |
171 m_moduleScript = | |
172 createModuleScript(sourceText, resource()->response().url(), m_modulator, | |
173 m_nonce, m_parserState, m_credentialsMode); | |
yhirano
2017/02/17 04:59:15
Can we use resource->resourceRequest().fetchCreden
kouhei (in TOK)
2017/02/21 01:26:50
Done.
| |
174 | |
175 advanceState(State::Finished); | |
176 setResource(nullptr); | |
177 } | |
178 | |
179 // https://html.spec.whatwg.org/#creating-a-module-script | |
180 ModuleScript* ModuleScriptLoader::createModuleScript( | |
181 const String& sourceText, | |
182 const KURL& url, | |
183 Modulator* modulator, | |
184 const String& nonce, | |
185 ParserDisposition parserState, | |
186 WebURLRequest::FetchCredentialsMode credentialsMode) { | |
187 // Step 1. Let script be a new module script that this algorithm will | |
188 // subsequently initialize. | |
189 // Step 2. Set script's settings object to the environment settings object | |
190 // provided. | |
191 // Note: "script's settings object" will be "modulator". | |
192 | |
193 // Delegate to Modulator::compileModule to process Steps 3-6. | |
194 ScriptModule record = modulator->compileModule(sourceText, url.getString()); | |
hiroshige
2017/02/20 23:15:32
nit: should this local variable's name |result| in
kouhei (in TOK)
2017/02/21 01:26:50
Done.
| |
195 if (record.isNull()) | |
196 return nullptr; | |
hiroshige
2017/02/20 23:15:32
Isn't this a part of Step 6: "...return null, and
kouhei (in TOK)
2017/02/21 01:26:51
Done.
| |
197 // Step 7. Set script's module record to result. | |
198 // Step 8. Set script's base URL to the script base URL provided. | |
199 // Step 9. Set script's cryptographic nonce to the cryptographic nonce | |
200 // provided. | |
201 // Step 10. Set script's parser state to the parser state. | |
202 // Step 11. Set script's credentials mode to the credentials mode provided. | |
203 // Step 12. Return script. | |
204 return ModuleScript::create(record, url, nonce, parserState, credentialsMode); | |
205 } | |
206 | |
207 DEFINE_TRACE(ModuleScriptLoader) { | |
208 visitor->trace(m_modulator); | |
209 visitor->trace(m_moduleScript); | |
210 visitor->trace(m_registry); | |
211 visitor->trace(m_client); | |
212 ResourceOwner<ScriptResource>::trace(visitor); | |
213 } | |
214 | |
215 } // namespace blink | |
OLD | NEW |