atom_api_net_log.cc 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. // Copyright (c) 2018 GitHub, Inc.
  2. // Use of this source code is governed by the MIT license that can be
  3. // found in the LICENSE file.
  4. #include "shell/browser/api/atom_api_net_log.h"
  5. #include <utility>
  6. #include "base/command_line.h"
  7. #include "chrome/browser/browser_process.h"
  8. #include "components/net_log/chrome_net_log.h"
  9. #include "content/public/browser/storage_partition.h"
  10. #include "electron/electron_version.h"
  11. #include "native_mate/converter.h"
  12. #include "native_mate/dictionary.h"
  13. #include "native_mate/handle.h"
  14. #include "shell/browser/atom_browser_context.h"
  15. #include "shell/browser/net/system_network_context_manager.h"
  16. #include "shell/common/native_mate_converters/callback.h"
  17. #include "shell/common/native_mate_converters/file_path_converter.h"
  18. #include "shell/common/node_includes.h"
  19. namespace mate {
  20. template <>
  21. struct Converter<net::NetLogCaptureMode> {
  22. static bool FromV8(v8::Isolate* isolate,
  23. v8::Local<v8::Value> val,
  24. net::NetLogCaptureMode* out) {
  25. std::string type;
  26. if (!ConvertFromV8(isolate, val, &type))
  27. return false;
  28. if (type == "default")
  29. *out = net::NetLogCaptureMode::kDefault;
  30. else if (type == "includeSensitive")
  31. *out = net::NetLogCaptureMode::kIncludeSensitive;
  32. else if (type == "everything")
  33. *out = net::NetLogCaptureMode::kEverything;
  34. else
  35. return false;
  36. return true;
  37. }
  38. };
  39. } // namespace mate
  40. namespace electron {
  41. namespace {
  42. scoped_refptr<base::SequencedTaskRunner> CreateFileTaskRunner() {
  43. // The tasks posted to this sequenced task runner do synchronous File I/O for
  44. // checking paths and setting permissions on files.
  45. //
  46. // These operations can be skipped on shutdown since FileNetLogObserver's API
  47. // doesn't require things to have completed until notified of completion.
  48. return base::CreateSequencedTaskRunner(
  49. {base::ThreadPool(), base::MayBlock(), base::TaskPriority::USER_VISIBLE,
  50. base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN});
  51. }
  52. base::File OpenFileForWriting(base::FilePath path) {
  53. return base::File(path,
  54. base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
  55. }
  56. void ResolvePromiseWithNetError(util::Promise promise, int32_t error) {
  57. if (error == net::OK) {
  58. promise.Resolve();
  59. } else {
  60. promise.RejectWithErrorMessage(net::ErrorToString(error));
  61. }
  62. }
  63. } // namespace
  64. namespace api {
  65. NetLog::NetLog(v8::Isolate* isolate, AtomBrowserContext* browser_context)
  66. : browser_context_(browser_context), weak_ptr_factory_(this) {
  67. Init(isolate);
  68. file_task_runner_ = CreateFileTaskRunner();
  69. }
  70. NetLog::~NetLog() = default;
  71. v8::Local<v8::Promise> NetLog::StartLogging(base::FilePath log_path,
  72. mate::Arguments* args) {
  73. if (log_path.empty()) {
  74. args->ThrowError("The first parameter must be a valid string");
  75. return v8::Local<v8::Promise>();
  76. }
  77. net::NetLogCaptureMode capture_mode = net::NetLogCaptureMode::kDefault;
  78. uint64_t max_file_size = network::mojom::NetLogExporter::kUnlimitedFileSize;
  79. mate::Dictionary dict;
  80. if (args->GetNext(&dict)) {
  81. v8::Local<v8::Value> capture_mode_v8;
  82. if (dict.Get("captureMode", &capture_mode_v8)) {
  83. if (!mate::ConvertFromV8(args->isolate(), capture_mode_v8,
  84. &capture_mode)) {
  85. args->ThrowError("Invalid value for captureMode");
  86. return v8::Local<v8::Promise>();
  87. }
  88. }
  89. v8::Local<v8::Value> max_file_size_v8;
  90. if (dict.Get("maxFileSize", &max_file_size_v8)) {
  91. if (!mate::ConvertFromV8(args->isolate(), max_file_size_v8,
  92. &max_file_size)) {
  93. args->ThrowError("Invalid value for maxFileSize");
  94. return v8::Local<v8::Promise>();
  95. }
  96. }
  97. }
  98. if (net_log_exporter_) {
  99. args->ThrowError("There is already a net log running");
  100. return v8::Local<v8::Promise>();
  101. }
  102. pending_start_promise_ = base::make_optional<util::Promise>(isolate());
  103. v8::Local<v8::Promise> handle = pending_start_promise_->GetHandle();
  104. auto command_line_string =
  105. base::CommandLine::ForCurrentProcess()->GetCommandLineString();
  106. auto channel_string = std::string("Electron " ELECTRON_VERSION);
  107. base::Value custom_constants =
  108. base::Value::FromUniquePtrValue(net_log::GetPlatformConstantsForNetLog(
  109. command_line_string, channel_string));
  110. auto* network_context =
  111. content::BrowserContext::GetDefaultStoragePartition(browser_context_)
  112. ->GetNetworkContext();
  113. network_context->CreateNetLogExporter(mojo::MakeRequest(&net_log_exporter_));
  114. net_log_exporter_.set_connection_error_handler(
  115. base::BindOnce(&NetLog::OnConnectionError, base::Unretained(this)));
  116. base::PostTaskAndReplyWithResult(
  117. file_task_runner_.get(), FROM_HERE,
  118. base::BindOnce(OpenFileForWriting, log_path),
  119. base::BindOnce(&NetLog::StartNetLogAfterCreateFile,
  120. weak_ptr_factory_.GetWeakPtr(), capture_mode,
  121. max_file_size, std::move(custom_constants)));
  122. return handle;
  123. }
  124. void NetLog::StartNetLogAfterCreateFile(net::NetLogCaptureMode capture_mode,
  125. uint64_t max_file_size,
  126. base::Value custom_constants,
  127. base::File output_file) {
  128. if (!net_log_exporter_) {
  129. // Theoretically the mojo pipe could have been closed by the time we get
  130. // here via the connection error handler. If so, the promise has already
  131. // been resolved.
  132. return;
  133. }
  134. DCHECK(pending_start_promise_);
  135. if (!output_file.IsValid()) {
  136. std::move(*pending_start_promise_)
  137. .RejectWithErrorMessage(
  138. base::File::ErrorToString(output_file.error_details()));
  139. net_log_exporter_.reset();
  140. return;
  141. }
  142. net_log_exporter_->Start(
  143. std::move(output_file), std::move(custom_constants), capture_mode,
  144. max_file_size,
  145. base::BindOnce(&NetLog::NetLogStarted, base::Unretained(this)));
  146. }
  147. void NetLog::NetLogStarted(int32_t error) {
  148. DCHECK(pending_start_promise_);
  149. ResolvePromiseWithNetError(std::move(*pending_start_promise_), error);
  150. }
  151. void NetLog::OnConnectionError() {
  152. net_log_exporter_.reset();
  153. if (pending_start_promise_) {
  154. std::move(*pending_start_promise_)
  155. .RejectWithErrorMessage("Failed to start net log exporter");
  156. }
  157. }
  158. bool NetLog::IsCurrentlyLogging() const {
  159. return !!net_log_exporter_;
  160. }
  161. v8::Local<v8::Promise> NetLog::StopLogging(mate::Arguments* args) {
  162. util::Promise promise(isolate());
  163. v8::Local<v8::Promise> handle = promise.GetHandle();
  164. if (net_log_exporter_) {
  165. // Move the net_log_exporter_ into the callback to ensure that the mojo
  166. // pointer lives long enough to resolve the promise. Moving it into the
  167. // callback will cause the instance variable to become empty.
  168. net_log_exporter_->Stop(
  169. base::Value(base::Value::Type::DICTIONARY),
  170. base::BindOnce(
  171. [](network::mojom::NetLogExporterPtr, util::Promise promise,
  172. int32_t error) {
  173. ResolvePromiseWithNetError(std::move(promise), error);
  174. },
  175. std::move(net_log_exporter_), std::move(promise)));
  176. } else {
  177. promise.RejectWithErrorMessage("No net log in progress");
  178. }
  179. return handle;
  180. }
  181. // static
  182. mate::Handle<NetLog> NetLog::Create(v8::Isolate* isolate,
  183. AtomBrowserContext* browser_context) {
  184. return mate::CreateHandle(isolate, new NetLog(isolate, browser_context));
  185. }
  186. // static
  187. void NetLog::BuildPrototype(v8::Isolate* isolate,
  188. v8::Local<v8::FunctionTemplate> prototype) {
  189. prototype->SetClassName(mate::StringToV8(isolate, "NetLog"));
  190. mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate())
  191. .SetProperty("currentlyLogging", &NetLog::IsCurrentlyLogging)
  192. .SetMethod("startLogging", &NetLog::StartLogging)
  193. .SetMethod("stopLogging", &NetLog::StopLogging);
  194. }
  195. } // namespace api
  196. } // namespace electron