OLD | NEW |
(Empty) | |
| 1 // Copyright 2014 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 #include "services/dart/content_handler_app.h" |
| 5 |
| 6 #include "base/message_loop/message_loop.h" |
| 7 #include "base/run_loop.h" |
| 8 #include "base/strings/string_split.h" |
| 9 #include "base/synchronization/waitable_event.h" |
| 10 #include "base/threading/platform_thread.h" |
| 11 #include "base/trace_event/trace_event.h" |
| 12 #include "mojo/dart/embedder/dart_controller.h" |
| 13 #include "mojo/public/cpp/application/application_impl.h" |
| 14 #include "mojo/public/cpp/application/connect.h" |
| 15 #include "mojo/public/cpp/bindings/binding.h" |
| 16 #include "mojo/public/cpp/bindings/interface_request.h" |
| 17 #include "mojo/services/tracing/interfaces/tracing.mojom.h" |
| 18 #include "services/dart/dart_app.h" |
| 19 #include "url/gurl.h" |
| 20 |
| 21 namespace dart { |
| 22 |
| 23 // Flags for the content handler: |
| 24 const char kDartTimeline[] = "--dart-timeline"; |
| 25 const char kDisableObservatory[] = "--disable-observatory"; |
| 26 const char kEnableStrictMode[] = "--enable-strict-mode"; |
| 27 const char kRunOnMessageLoop[] = "--run-on-message-loop"; |
| 28 const char kTraceStartup[] = "--trace-startup"; |
| 29 // Flags forwarded to the Dart VM: |
| 30 const char kCompleteTimeline[] = "--complete-timeline"; |
| 31 const char kPauseIsolatesOnStart[] = "--pause-isolates-on-start"; |
| 32 const char kPauseIsolatesOnExit[] = "--pause-isolates-on-exit"; |
| 33 |
| 34 static bool IsDartZip(std::string url) { |
| 35 // If the url doesn't end with ".dart" we assume it is a zipped up |
| 36 // dart application. |
| 37 return !base::EndsWith(url, ".dart", base::CompareCase::INSENSITIVE_ASCII); |
| 38 } |
| 39 |
| 40 // Returns true if |requestedUrl| has a boolean query parameter named |param|. |
| 41 static bool HasBoolQueryParam(const std::string& requestedUrl, |
| 42 const std::string& param) { |
| 43 std::string param_true = param + "=true"; |
| 44 std::string param_false = param + "=false"; |
| 45 |
| 46 GURL url(requestedUrl); |
| 47 if (url.has_query()) { |
| 48 std::vector<std::string> query_parameters = base::SplitString( |
| 49 url.query(), "&", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY); |
| 50 bool has_true = std::find(query_parameters.begin(), query_parameters.end(), |
| 51 param_true) != query_parameters.end(); |
| 52 bool has_false = std::find(query_parameters.begin(), query_parameters.end(), |
| 53 param_false) != query_parameters.end(); |
| 54 return has_true || has_false; |
| 55 } |
| 56 return false; |
| 57 } |
| 58 |
| 59 // Returns the value of the boolean query parameter named |param|, or |
| 60 // |default_value| if it |param| is not present. |
| 61 static bool BoolQueryParamValue(const std::string& requestedUrl, |
| 62 const std::string& param, |
| 63 bool default_value) { |
| 64 if (!HasBoolQueryParam(requestedUrl, param)) { |
| 65 return default_value; |
| 66 } |
| 67 std::string param_true = param + "=true"; |
| 68 std::string param_false = param + "=false"; |
| 69 GURL url(requestedUrl); |
| 70 DCHECK(url.has_query()); |
| 71 std::vector<std::string> query_parameters = base::SplitString( |
| 72 url.query(), "&", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY); |
| 73 bool has_true = std::find(query_parameters.begin(), query_parameters.end(), |
| 74 param_true) != query_parameters.end(); |
| 75 bool has_false = std::find(query_parameters.begin(), query_parameters.end(), |
| 76 param_false) != query_parameters.end(); |
| 77 if (has_true) { |
| 78 return has_true; |
| 79 } |
| 80 if (has_false) { |
| 81 return false; |
| 82 } |
| 83 return default_value; |
| 84 } |
| 85 |
| 86 static bool HasStrictQueryParam(const std::string& requestedUrl) { |
| 87 return BoolQueryParamValue(requestedUrl, "strict", false); |
| 88 } |
| 89 |
| 90 DartContentHandler::DartContentHandler(DartContentHandlerApp* app, bool strict) |
| 91 : app_(app), strict_(strict) {} |
| 92 |
| 93 void DartContentHandler::set_handler_task_runner( |
| 94 scoped_refptr<base::SingleThreadTaskRunner> handler_task_runner) { |
| 95 handler_task_runner_ = handler_task_runner; |
| 96 } |
| 97 |
| 98 DartContentHandlerApp::DartContentHandlerApp() |
| 99 : content_handler_(this, false), |
| 100 strict_content_handler_(this, true), |
| 101 service_connector_(nullptr), |
| 102 default_strict_(false), |
| 103 run_on_message_loop_(false) {} |
| 104 |
| 105 DartContentHandlerApp::~DartContentHandlerApp() { |
| 106 // Shutdown the controller. |
| 107 mojo::dart::DartController::Shutdown(); |
| 108 delete service_connector_; |
| 109 } |
| 110 |
| 111 void DartContentHandlerApp::ExtractApplication(base::FilePath* application_dir, |
| 112 mojo::URLResponsePtr response, |
| 113 const base::Closure& callback) { |
| 114 url_response_disk_cache_->UpdateAndGetExtracted( |
| 115 response.Pass(), |
| 116 [application_dir, callback](mojo::Array<uint8_t> application_dir_path, |
| 117 mojo::Array<uint8_t> cache_path) { |
| 118 if (application_dir_path.is_null()) { |
| 119 *application_dir = base::FilePath(); |
| 120 } else { |
| 121 *application_dir = base::FilePath(std::string( |
| 122 reinterpret_cast<char*>(&application_dir_path.front()), |
| 123 application_dir_path.size())); |
| 124 } |
| 125 callback.Run(); |
| 126 }); |
| 127 } |
| 128 |
| 129 bool DartContentHandlerApp::run_on_message_loop() const { |
| 130 return run_on_message_loop_; |
| 131 } |
| 132 |
| 133 void DartContentHandlerApp::Initialize(mojo::ApplicationImpl* app) { |
| 134 // Tracing of content handler and controller. |
| 135 tracing_.Initialize(app); |
| 136 // Tracing of isolates and VM. |
| 137 dart_tracing_.Initialize(app); |
| 138 |
| 139 // TODO(qsr): This has no effect for now, as the tracing infrastructure |
| 140 // doesn't allow to trace anything before the tracing app connects to the |
| 141 // application. |
| 142 TRACE_EVENT0("dart_content_handler", "DartContentHandler::Initialize"); |
| 143 |
| 144 default_strict_ = app->HasArg(kEnableStrictMode); |
| 145 content_handler_.set_handler_task_runner( |
| 146 base::MessageLoop::current()->task_runner()); |
| 147 strict_content_handler_.set_handler_task_runner( |
| 148 base::MessageLoop::current()->task_runner()); |
| 149 mojo::ConnectToService(app->shell(), "mojo:url_response_disk_cache", |
| 150 GetProxy(&url_response_disk_cache_)); |
| 151 service_connector_ = new ContentHandlerAppServiceConnector(app); |
| 152 |
| 153 if (app->HasArg(kRunOnMessageLoop)) { |
| 154 run_on_message_loop_ = true; |
| 155 } |
| 156 |
| 157 bool enable_observatory = true; |
| 158 if (app->HasArg(kDisableObservatory)) { |
| 159 enable_observatory = false; |
| 160 } |
| 161 |
| 162 bool enable_dart_timeline = false; |
| 163 if (app->HasArg(kDartTimeline)) { |
| 164 enable_dart_timeline = true; |
| 165 } |
| 166 |
| 167 std::vector<const char*> extra_args; |
| 168 |
| 169 if (app->HasArg(kPauseIsolatesOnStart)) { |
| 170 extra_args.push_back(kPauseIsolatesOnStart); |
| 171 } |
| 172 |
| 173 if (app->HasArg(kPauseIsolatesOnExit)) { |
| 174 extra_args.push_back(kPauseIsolatesOnExit); |
| 175 } |
| 176 |
| 177 if (app->HasArg(kCompleteTimeline)) { |
| 178 extra_args.push_back(kCompleteTimeline); |
| 179 } |
| 180 |
| 181 bool success = mojo::dart::DartController::Initialize( |
| 182 service_connector_, default_strict_, enable_observatory, |
| 183 enable_dart_timeline, extra_args.data(), extra_args.size()); |
| 184 |
| 185 if (app->HasArg(kTraceStartup)) { |
| 186 DartTimelineController::EnableAll(); |
| 187 } |
| 188 if (!success) { |
| 189 LOG(ERROR) << "Dart VM Initialization failed"; |
| 190 } |
| 191 } |
| 192 |
| 193 bool DartContentHandlerApp::ConfigureIncomingConnection( |
| 194 mojo::ServiceProviderImpl* service_provider_impl) { |
| 195 bool strict = HasStrictQueryParam( |
| 196 service_provider_impl->connection_context().connection_url); |
| 197 if (default_strict_ || strict) { |
| 198 service_provider_impl->AddService<mojo::ContentHandler>( |
| 199 mojo::ContentHandlerFactory::GetInterfaceRequestHandler( |
| 200 &strict_content_handler_)); |
| 201 } else { |
| 202 service_provider_impl->AddService<mojo::ContentHandler>( |
| 203 mojo::ContentHandlerFactory::GetInterfaceRequestHandler( |
| 204 &content_handler_)); |
| 205 } |
| 206 return true; |
| 207 } |
| 208 |
| 209 scoped_ptr<mojo::ContentHandlerFactory::HandledApplicationHolder> |
| 210 DartContentHandler::CreateApplication( |
| 211 mojo::InterfaceRequest<mojo::Application> application_request, |
| 212 mojo::URLResponsePtr response) { |
| 213 base::trace_event::TraceLog::GetInstance() |
| 214 ->SetCurrentThreadBlocksMessageLoop(); |
| 215 |
| 216 TRACE_EVENT1("dart_content_handler", "DartContentHandler::CreateApplication", |
| 217 "url", response->url.get()); |
| 218 |
| 219 const bool run_on_message_loop = app_->run_on_message_loop(); |
| 220 base::FilePath application_dir; |
| 221 std::string url = response->url.get(); |
| 222 const char* kPauseIsolatesOnStart = "pauseIsolatesOnStart"; |
| 223 const char* kPauseIsolatesOnExit = "pauseIsolatesOnExit"; |
| 224 const bool override_pause_isolates_flags = |
| 225 HasBoolQueryParam(url, kPauseIsolatesOnStart) || |
| 226 HasBoolQueryParam(url, kPauseIsolatesOnExit); |
| 227 const bool pause_isolates_on_start = BoolQueryParamValue( |
| 228 url, kPauseIsolatesOnStart, |
| 229 mojo::dart::DartControllerConfig::kDefaultPauseOnStart); |
| 230 const bool pause_isolates_on_exit = BoolQueryParamValue( |
| 231 url, kPauseIsolatesOnExit, |
| 232 mojo::dart::DartControllerConfig::kDefaultPauseOnExit); |
| 233 if (IsDartZip(response->url.get())) { |
| 234 // Loading a zipped snapshot: |
| 235 // 1) Extract the zip file. |
| 236 // 2) Launch from temporary directory (|application_dir|). |
| 237 handler_task_runner_->PostTask( |
| 238 FROM_HERE, |
| 239 base::Bind( |
| 240 &DartContentHandlerApp::ExtractApplication, base::Unretained(app_), |
| 241 base::Unretained(&application_dir), base::Passed(response.Pass()), |
| 242 base::Bind( |
| 243 base::IgnoreResult(&base::SingleThreadTaskRunner::PostTask), |
| 244 base::MessageLoop::current()->task_runner(), FROM_HERE, |
| 245 base::MessageLoop::QuitWhenIdleClosure()))); |
| 246 base::RunLoop().Run(); |
| 247 return make_scoped_ptr( |
| 248 new DartApp(application_request.Pass(), url, application_dir, strict_, |
| 249 run_on_message_loop, override_pause_isolates_flags, |
| 250 pause_isolates_on_start, pause_isolates_on_exit)); |
| 251 } else { |
| 252 // Loading a raw .dart file pointed at by |url|. |
| 253 return make_scoped_ptr( |
| 254 new DartApp(application_request.Pass(), url, strict_, |
| 255 run_on_message_loop, override_pause_isolates_flags, |
| 256 pause_isolates_on_start, pause_isolates_on_exit)); |
| 257 } |
| 258 } |
| 259 |
| 260 } // namespace dart |
OLD | NEW |