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 nullptr; |
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)) { | |
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_ == nullptr) { |
Mark Seaborn
2015/09/03 06:33:16
"!irt_fp_" is the normal style for Chromium code.
Sean Klein
2015/09/03 15:51:50
Done.
| |
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 == nullptr) { | |
Mark Seaborn
2015/09/03 06:33:16
Ditto: "!nexe_fp"
Sean Klein
2015/09/03 15:51:50
Done.
| |
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_.release()); |
142 NaClDesc* irt_desc = NaClDescFromNexePath(irt_path_); | 141 NaClDesc* nexe_desc = FileStreamToNaClDesc(nexe_fp.release()); |
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, nullptr, |
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 |