Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/files/file_path.h" | |
| 6 #include "base/files/file_util.h" | 5 #include "base/files/file_util.h" |
| 6 #include "base/files/scoped_file.h" | |
| 7 #include "base/message_loop/message_loop.h" | 7 #include "base/message_loop/message_loop.h" |
| 8 #include "build/build_config.h" | 8 #include "build/build_config.h" |
| 9 #include "mojo/application/application_runner_chromium.h" | 9 #include "mojo/application/application_runner_chromium.h" |
| 10 #include "mojo/application/content_handler_factory.h" | 10 #include "mojo/application/content_handler_factory.h" |
| 11 #include "mojo/data_pipe_utils/data_pipe_utils.h" | 11 #include "mojo/data_pipe_utils/data_pipe_utils.h" |
| 12 #include "mojo/message_pump/message_pump_mojo.h" | 12 #include "mojo/message_pump/message_pump_mojo.h" |
| 13 #include "mojo/public/c/system/main.h" | 13 #include "mojo/public/c/system/main.h" |
| 14 #include "mojo/public/cpp/application/application_connection.h" | 14 #include "mojo/public/cpp/application/application_connection.h" |
| 15 #include "mojo/public/cpp/application/application_delegate.h" | 15 #include "mojo/public/cpp/application/application_delegate.h" |
| 16 #include "mojo/public/cpp/application/application_impl.h" | 16 #include "mojo/public/cpp/application/application_impl.h" |
| 17 #include "mojo/services/network/public/interfaces/network_service.mojom.h" | 17 #include "mojo/services/network/public/interfaces/network_service.mojom.h" |
| 18 #include "mojo/services/network/public/interfaces/url_loader.mojom.h" | 18 #include "mojo/services/network/public/interfaces/url_loader.mojom.h" |
| 19 #include "nacl_bindings/monacl_sel_main.h" | 19 #include "nacl_bindings/monacl_sel_main.h" |
| 20 #include "native_client/src/public/nacl_desc.h" | 20 #include "native_client/src/public/nacl_desc.h" |
| 21 #include "url/gurl.h" | 21 #include "url/gurl.h" |
| 22 | 22 |
| 23 namespace nacl { | 23 namespace nacl { |
| 24 namespace content_handler { | 24 namespace content_handler { |
| 25 | 25 |
| 26 namespace { | 26 namespace { |
| 27 bool URLResponseToTempFile(mojo::URLResponsePtr& response, | 27 base::ScopedFILE TempFileForURL(mojo::URLLoaderPtr& url_loader, |
| 28 base::FilePath* file_path) { | 28 const GURL& url) { |
| 29 if (!base::CreateTemporaryFile(file_path)) { | |
| 30 return false; | |
| 31 } | |
| 32 | |
| 33 if (!mojo::common::BlockingCopyToFile(response->body.Pass(), *file_path)) { | |
| 34 base::DeleteFile(*file_path, false); | |
| 35 return false; | |
| 36 } | |
| 37 | |
| 38 // TODO(ncbray): can we ensure temp file deletion even if we crash? | |
| 39 return true; | |
| 40 } | |
| 41 | |
| 42 bool TempFileForURL(mojo::URLLoaderPtr& url_loader, | |
| 43 const GURL& url, | |
| 44 base::FilePath* path) { | |
| 45 mojo::URLRequestPtr request(mojo::URLRequest::New()); | 29 mojo::URLRequestPtr request(mojo::URLRequest::New()); |
| 46 request->url = url.spec(); | 30 request->url = url.spec(); |
| 47 request->method = "GET"; | 31 request->method = "GET"; |
| 48 request->auto_follow_redirects = true; | 32 request->auto_follow_redirects = true; |
| 49 | 33 |
| 50 // Handle the callback synchonously. | 34 // Handle the callback synchonously. |
| 51 mojo::URLResponsePtr response; | 35 mojo::URLResponsePtr response; |
| 52 url_loader->Start(request.Pass(), [&response](mojo::URLResponsePtr r) { | 36 url_loader->Start(request.Pass(), [&response](mojo::URLResponsePtr r) { |
| 53 response = r.Pass(); | 37 response = r.Pass(); |
| 54 }); | 38 }); |
| 55 url_loader.WaitForIncomingResponse(); | 39 url_loader.WaitForIncomingResponse(); |
| 56 if (response.is_null()) { | 40 if (response.is_null()) { |
| 57 LOG(FATAL) << "something went horribly wrong (missed a callback?)"; | 41 LOG(FATAL) << "something went horribly wrong (missed a callback?)"; |
| 58 } | 42 } |
| 59 | 43 |
| 60 if (response->error) { | 44 if (response->error) { |
| 61 LOG(ERROR) << "could not load " << url.spec() << " (" | 45 LOG(ERROR) << "could not load " << url.spec() << " (" |
| 62 << response->error->code << ") " | 46 << response->error->code << ") " |
| 63 << response->error->description.get().c_str(); | 47 << response->error->description.get().c_str(); |
| 64 return false; | 48 return NULL; |
| 65 } | 49 } |
| 66 | 50 |
| 67 return URLResponseToTempFile(response, path); | 51 return mojo::common::BlockingCopyToTempFile(response->body.Pass()); |
| 68 } | 52 } |
| 69 | 53 |
| 70 NaClDesc* NaClDescFromNexePath(base::FilePath& path) { | 54 NaClDesc* FileStreamToNaClDesc(FILE* file_stream) { |
| 71 base::File file(path, base::File::FLAG_OPEN | base::File::FLAG_READ | | 55 // Get file handle |
| 72 base::File::FLAG_EXECUTE); | 56 int fd = fileno(file_stream); |
| 73 if (!file.IsValid()) { | 57 if (fd == -1) { |
| 74 LOG(FATAL) << "failed to open " << path.value(); | 58 LOG(FATAL) << "Could not open the stream pointer's file descriptor"; |
| 75 } | 59 } |
| 76 // Note: potentially unsafe, assumes the file is immutable. This should be | 60 |
| 77 // OK because we're currently only using temp files. | 61 // These file descriptors must be dup'd, since NaClDesc takes ownership |
| 78 return NaClDescCreateWithFilePathMetadata(file.TakePlatformFile(), | 62 // of the file descriptor. The descriptor is still needed to close |
| 79 path.AsUTF8Unsafe().c_str()); | 63 // the file stream. |
| 64 fd = dup(fd); | |
| 65 if (fd == -1) { | |
| 66 LOG(FATAL) << "Could not dup the file descriptor"; | |
| 67 } | |
| 68 | |
| 69 NaClDesc* desc = NaClDescCreateWithFilePathMetadata(fd, ""); | |
| 70 | |
| 71 // Clean up. | |
| 72 if (fclose(file_stream)) { | |
|
Sean Klein
2015/09/02 21:49:11
Is this still necessary with a ScopedFILE?
Mark Seaborn
2015/09/02 22:50:35
No. This fclose() currently isn't right because t
Sean Klein
2015/09/02 23:25:53
Done.
| |
| 73 LOG(FATAL) << "Failed to close temp file"; | |
| 74 } | |
| 75 | |
| 76 return desc; | |
| 80 } | 77 } |
| 81 | 78 |
| 82 } // namespace | 79 } // namespace |
| 83 | 80 |
| 84 class NaClContentHandler : public mojo::ApplicationDelegate, | 81 class NaClContentHandler : public mojo::ApplicationDelegate, |
| 85 public mojo::ContentHandlerFactory::Delegate { | 82 public mojo::ContentHandlerFactory::Delegate { |
| 86 public: | 83 public: |
| 87 NaClContentHandler() : content_handler_factory_(this) {} | 84 NaClContentHandler() : content_handler_factory_(this) {} |
| 88 | 85 |
| 89 private: | 86 private: |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 102 GURL irt_url; | 99 GURL irt_url; |
| 103 #if defined(ARCH_CPU_X86_64) | 100 #if defined(ARCH_CPU_X86_64) |
| 104 irt_url = url_.Resolve("irt_x64/irt_mojo.nexe"); | 101 irt_url = url_.Resolve("irt_x64/irt_mojo.nexe"); |
| 105 #else | 102 #else |
| 106 #error "Unknown / unsupported CPU architecture." | 103 #error "Unknown / unsupported CPU architecture." |
| 107 #endif | 104 #endif |
| 108 if (!irt_url.is_valid()) { | 105 if (!irt_url.is_valid()) { |
| 109 LOG(FATAL) << "Cannot resolve IRT URL"; | 106 LOG(FATAL) << "Cannot resolve IRT URL"; |
| 110 } | 107 } |
| 111 | 108 |
| 112 if (!TempFileForURL(url_loader, irt_url, &irt_path_)) { | 109 irt_fp_ = TempFileForURL(url_loader, irt_url); |
| 113 LOG(FATAL) << "Could not aquire the IRT"; | 110 if (irt_fp_ == NULL) { |
| 111 LOG(FATAL) << "Could not acquire the IRT"; | |
| 114 } | 112 } |
| 115 } | 113 } |
| 116 | 114 |
| 117 // Overridden from ApplicationDelegate: | 115 // Overridden from ApplicationDelegate: |
| 118 bool ConfigureIncomingConnection( | 116 bool ConfigureIncomingConnection( |
| 119 mojo::ApplicationConnection* connection) override { | 117 mojo::ApplicationConnection* connection) override { |
| 120 connection->AddService(&content_handler_factory_); | 118 connection->AddService(&content_handler_factory_); |
| 121 return true; | 119 return true; |
| 122 } | 120 } |
| 123 | 121 |
| 124 // Overridden from ContentHandlerFactory::ManagedDelegate: | 122 // Overridden from ContentHandlerFactory::ManagedDelegate: |
| 125 void RunApplication( | 123 void RunApplication( |
| 126 mojo::InterfaceRequest<mojo::Application> application_request, | 124 mojo::InterfaceRequest<mojo::Application> application_request, |
| 127 mojo::URLResponsePtr response) override { | 125 mojo::URLResponsePtr response) override { |
| 128 // Needed to use Mojo interfaces on this thread. | 126 // Needed to use Mojo interfaces on this thread. |
| 129 base::MessageLoop loop(mojo::common::MessagePumpMojo::Create()); | 127 base::MessageLoop loop(mojo::common::MessagePumpMojo::Create()); |
| 130 | 128 |
| 131 // Aquire the nexe. | 129 // Acquire the nexe. |
| 132 base::FilePath nexe_path; | 130 base::ScopedFILE nexe_fp = |
| 133 if (!URLResponseToTempFile(response, &nexe_path)) { | 131 mojo::common::BlockingCopyToTempFile(response->body.Pass()); |
| 132 if (nexe_fp == NULL) { | |
| 134 LOG(FATAL) << "could not redirect nexe to temp file"; | 133 LOG(FATAL) << "could not redirect nexe to temp file"; |
| 135 } | 134 } |
| 136 | 135 |
| 137 // Aquire the IRT. | 136 // Acquire the IRT. |
| 138 mojo::URLLoaderPtr url_loader = url_loader_.Pass(); | 137 mojo::URLLoaderPtr url_loader = url_loader_.Pass(); |
| 139 LoadIRT(url_loader); | 138 LoadIRT(url_loader); |
| 140 | 139 |
| 141 // Get file handles to the IRT and nexe. | 140 NaClDesc* irt_desc = FileStreamToNaClDesc(irt_fp_.get()); |
|
Mark Seaborn
2015/09/02 22:50:35
I think you can use release() instead of get() for
Sean Klein
2015/09/02 23:25:53
Done.
| |
| 142 NaClDesc* irt_desc = NaClDescFromNexePath(irt_path_); | 141 NaClDesc* nexe_desc = FileStreamToNaClDesc(nexe_fp.get()); |
| 143 NaClDesc* nexe_desc = NaClDescFromNexePath(nexe_path); | |
| 144 | 142 |
| 145 // Run. | 143 // Run. |
| 146 int exit_code = mojo::LaunchNaCl( | 144 int exit_code = mojo::LaunchNaCl( |
| 147 nexe_desc, irt_desc, 0, NULL, | 145 nexe_desc, irt_desc, 0, NULL, |
| 148 application_request.PassMessagePipe().release().value()); | 146 application_request.PassMessagePipe().release().value()); |
| 149 | 147 |
| 150 // TODO(ncbray): are the file handles actually closed at this point? | |
| 151 | |
| 152 // Clean up. | |
| 153 if (!base::DeleteFile(irt_path_, false)) { | |
| 154 LOG(FATAL) << "Failed to remove irt temp file " << irt_path_.value(); | |
| 155 } | |
| 156 if (!base::DeleteFile(nexe_path, false)) { | |
| 157 LOG(FATAL) << "Failed to remove nexe temp file " << nexe_path.value(); | |
| 158 } | |
| 159 | |
| 160 // Exits the process cleanly, does not return. | 148 // Exits the process cleanly, does not return. |
| 161 mojo::NaClExit(exit_code); | 149 mojo::NaClExit(exit_code); |
| 162 NOTREACHED(); | 150 NOTREACHED(); |
| 163 } | 151 } |
| 164 | 152 |
| 165 mojo::ContentHandlerFactory content_handler_factory_; | 153 mojo::ContentHandlerFactory content_handler_factory_; |
| 166 GURL url_; | 154 GURL url_; |
| 167 base::FilePath irt_path_; | 155 base::ScopedFILE irt_fp_; |
| 168 | 156 |
| 169 mojo::URLLoaderPtr url_loader_; | 157 mojo::URLLoaderPtr url_loader_; |
| 170 | 158 |
| 171 DISALLOW_COPY_AND_ASSIGN(NaClContentHandler); | 159 DISALLOW_COPY_AND_ASSIGN(NaClContentHandler); |
| 172 }; | 160 }; |
| 173 | 161 |
| 174 } // namespace content_handler | 162 } // namespace content_handler |
| 175 } // namespace nacl | 163 } // namespace nacl |
| 176 | 164 |
| 177 MojoResult MojoMain(MojoHandle application_request) { | 165 MojoResult MojoMain(MojoHandle application_request) { |
| 178 mojo::ApplicationRunnerChromium runner( | 166 mojo::ApplicationRunnerChromium runner( |
| 179 new nacl::content_handler::NaClContentHandler()); | 167 new nacl::content_handler::NaClContentHandler()); |
| 180 return runner.Run(application_request); | 168 return runner.Run(application_request); |
| 181 } | 169 } |
| OLD | NEW |