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/fetch/ResourceFetcher.h" |
| 10 #include "core/loader/modulescript/ModuleScriptLoaderClient.h" |
| 11 #include "core/loader/modulescript/ModuleScriptLoaderRegistry.h" |
| 12 #include "platform/network/mime/MIMETypeRegistry.h" |
| 13 |
| 14 namespace blink { |
| 15 |
| 16 ModuleScriptLoader::ModuleScriptLoader(const KURL& url, |
| 17 const KURL& baseURL, |
| 18 Modulator* modulator, |
| 19 ModuleScriptLoaderRegistry* registry, |
| 20 ModuleScriptLoaderClient* client) |
| 21 : m_url(url), |
| 22 m_baseURL(url), |
| 23 m_modulator(modulator), |
| 24 m_registry(registry), |
| 25 m_client(client) { |
| 26 DCHECK(modulator); |
| 27 DCHECK(registry); |
| 28 DCHECK(client); |
| 29 } |
| 30 |
| 31 ModuleScriptLoader::~ModuleScriptLoader() {} |
| 32 |
| 33 void ModuleScriptLoader::advanceState(ModuleScriptLoader::State newState) { |
| 34 switch (m_state) { |
| 35 case State::Initial: |
| 36 DCHECK_EQ(newState, State::Fetching); |
| 37 break; |
| 38 case State::Fetching: |
| 39 DCHECK_EQ(newState, State::Finished); |
| 40 break; |
| 41 case State::Finished: |
| 42 NOTREACHED(); |
| 43 break; |
| 44 default: |
| 45 NOTREACHED(); |
| 46 } |
| 47 |
| 48 m_state = newState; |
| 49 |
| 50 if (m_state == State::Finished) { |
| 51 m_registry->releaseFinishedLoader(this); |
| 52 m_client->notifyFinishedNewSingleModule(m_moduleScript); |
| 53 } |
| 54 } |
| 55 |
| 56 void ModuleScriptLoader::fetch(ResourceFetcher* fetcher) { |
| 57 // Step 4. Set moduleMap[url] to "fetching". |
| 58 advanceState(State::Fetching); |
| 59 |
| 60 // Step 5. Let request be a new request whose url is url, destination is |
| 61 // destination, type is "script", mode is "cors", credentials mode is |
| 62 // credentials mode, cryptographic nonce metadata is cryptographic nonce, |
| 63 // parser metadata is parser state, referrer is referrer, and client is |
| 64 // fetch client settings object. |
| 65 FetchRequest request(ResourceRequest(m_url), "module"); |
| 66 |
| 67 // Modules are always async |
| 68 request.setDefer(FetchRequest::LazyLoad); |
| 69 ScriptResource* resource = ScriptResource::fetch(request, fetcher); |
| 70 setResource(resource); |
| 71 |
| 72 // Step 6. If the caller specified custom steps to perform the fetch, |
| 73 // perform |
| 74 // them on request, setting the is top-level flag if the top-level module |
| 75 // fetch flag is set. Return from this algorithm, and when the custom |
| 76 // perform |
| 77 // the fetch steps complete with response response, run the remaining steps. |
| 78 // Otherwise, fetch request. Return from this algorithm, and run the |
| 79 // remaining |
| 80 // steps as part of the fetch's process response for the response response. |
| 81 // Note: response is always CORS-same-origin. |
| 82 |
| 83 // TODO(kouhei): I don't know what Step 6 means. ScriptLoader seems to |
| 84 // ignore the step? |
| 85 } |
| 86 |
| 87 bool ModuleScriptLoader::wasModuleLoadSuccessful(Resource* resource) { |
| 88 // Implements conditions in Step 7 of |
| 89 // https://html.spec.whatwg.org/#fetch-a-single-module-script |
| 90 |
| 91 // - response's type is "error" |
| 92 if (resource->errorOccurred()) |
| 93 return false; |
| 94 |
| 95 const auto& response = resource->response(); |
| 96 // - response's status is not an ok status |
| 97 if (response.isHTTP() && |
| 98 (response.httpStatusCode() < 200 || response.httpStatusCode() >= 300)) { |
| 99 return false; |
| 100 } |
| 101 |
| 102 // The result of extracting a MIME type from response's header list |
| 103 // (ignoring parameters) is not a JavaScript MIME type |
| 104 // Note: For historical reasons, fetching a classic script does not include |
| 105 // MIME type checking. In contrast, module scripts will fail to load if they |
| 106 // are not of a correct MIME type. |
| 107 if (!MIMETypeRegistry::isSupportedJavaScriptMIMEType(response.mimeType())) |
| 108 return false; |
| 109 |
| 110 return true; |
| 111 } |
| 112 |
| 113 // ScriptResourceClient callback handler |
| 114 void ModuleScriptLoader::notifyFinished(Resource*) { |
| 115 printf("notifyFinished!\n"); |
| 116 |
| 117 // Note: "conditions" referred in Step 7 is implemented in |
| 118 // wasModuleLoadSuccessful(). |
| 119 // Step 7. If any of the following conditions are met, set moduleMap[url] to |
| 120 // null, asynchronously complete this algorithm with null, and abort these |
| 121 // steps. |
| 122 if (!wasModuleLoadSuccessful(resource())) { |
| 123 printf("notifyFinished but load was not successful\n"); |
| 124 |
| 125 advanceState(State::Finished); |
| 126 setResource(nullptr); |
| 127 return; |
| 128 } |
| 129 |
| 130 // Step 8. Let source text be the result of UTF-8 decoding response's body. |
| 131 String script = resource()->script(); |
| 132 printf("fetched script: %s\n", script.utf8().data()); |
| 133 |
| 134 // Step 9. Let module script be the result of creating a module script given |
| 135 // source text, module map settings object, response's url, cryptographic |
| 136 // nonce, parser state, and credentials mode. |
| 137 |
| 138 // TODO(kouhei): post a task to compile module? |
| 139 ScriptModule record = m_modulator->compileModule(script, m_url.getString()); |
| 140 m_moduleScript = ModuleScript::create(record, m_baseURL); |
| 141 advanceState(State::Finished); |
| 142 setResource(nullptr); |
| 143 } |
| 144 |
| 145 DEFINE_TRACE(ModuleScriptLoader) { |
| 146 visitor->trace(m_modulator); |
| 147 visitor->trace(m_moduleScript); |
| 148 visitor->trace(m_registry); |
| 149 visitor->trace(m_client); |
| 150 ResourceOwner<ScriptResource>::trace(visitor); |
| 151 } |
| 152 |
| 153 } // namespace blink |
OLD | NEW |