From 477661d0e4e545e2562a8f8116f6bfad2d70231c Mon Sep 17 00:00:00 2001 From: Jeremy Apthorp Date: Thu, 25 Jul 2019 16:06:39 -0700 Subject: [PATCH] feat: allow setting capture mode and max file size in netLog API (#19215) --- docs/api/net-log.md | 10 ++++- lib/browser/api/session.js | 4 +- shell/browser/api/atom_api_net_log.cc | 59 +++++++++++++++++++++++---- shell/browser/api/atom_api_net_log.h | 3 +- spec-main/api-net-log-spec.js | 39 +++++++++++++++++- 5 files changed, 102 insertions(+), 13 deletions(-) diff --git a/docs/api/net-log.md b/docs/api/net-log.md index 6800639011a..6d024347ad8 100644 --- a/docs/api/net-log.md +++ b/docs/api/net-log.md @@ -22,9 +22,17 @@ of the `app` module gets emitted. ## Methods -### `netLog.startLogging(path)` +### `netLog.startLogging(path[, options])` * `path` String - File path to record network logs. +* `options` Object (optional) + * `captureMode` String (optional) - What kinds of data should be captured. By + default, only metadata about requests will be captured. Setting this to + `includeSensitive` will include cookies and authentication data. Setting + it to `everything` will include all bytes transferred on sockets. Can be + `default`, `includeSensitive` or `everything`. + * `maxFileSize` Number (optional) - When the log grows beyond this size, + logging will automatically stop. Defaults to unlimited. Returns `Promise` - resolves when the net log has begun recording. diff --git a/lib/browser/api/session.js b/lib/browser/api/session.js index 351cdb43658..9c058864060 100644 --- a/lib/browser/api/session.js +++ b/lib/browser/api/session.js @@ -24,10 +24,10 @@ Session.prototype._init = function () { } const _originalStartLogging = NetLog.prototype.startLogging -NetLog.prototype.startLogging = function (path) { +NetLog.prototype.startLogging = function (path, ...args) { this._currentlyLoggingPath = path try { - return _originalStartLogging.call(this, path) + return _originalStartLogging.call(this, path, ...args) } catch (e) { this._currentlyLoggingPath = null throw e diff --git a/shell/browser/api/atom_api_net_log.cc b/shell/browser/api/atom_api_net_log.cc index 1b177397ce9..24a222fdb1f 100644 --- a/shell/browser/api/atom_api_net_log.cc +++ b/shell/browser/api/atom_api_net_log.cc @@ -11,6 +11,7 @@ #include "components/net_log/chrome_net_log.h" #include "content/public/browser/storage_partition.h" #include "electron/electron_version.h" +#include "native_mate/converter.h" #include "native_mate/dictionary.h" #include "native_mate/handle.h" #include "net/url_request/url_request_context_getter.h" @@ -20,6 +21,30 @@ #include "shell/common/native_mate_converters/file_path_converter.h" #include "shell/common/node_includes.h" +namespace mate { + +template <> +struct Converter { + static bool FromV8(v8::Isolate* isolate, + v8::Local val, + net::NetLogCaptureMode* out) { + std::string type; + if (!ConvertFromV8(isolate, val, &type)) + return false; + if (type == "default") + *out = net::NetLogCaptureMode::kDefault; + else if (type == "includeSensitive") + *out = net::NetLogCaptureMode::kIncludeSensitive; + else if (type == "everything") + *out = net::NetLogCaptureMode::kEverything; + else + return false; + return true; + } +}; + +} // namespace mate + namespace electron { namespace { @@ -60,13 +85,36 @@ NetLog::NetLog(v8::Isolate* isolate, AtomBrowserContext* browser_context) NetLog::~NetLog() = default; -v8::Local NetLog::StartLogging(mate::Arguments* args) { - base::FilePath log_path; - if (!args->GetNext(&log_path) || log_path.empty()) { +v8::Local NetLog::StartLogging(base::FilePath log_path, + mate::Arguments* args) { + if (log_path.empty()) { args->ThrowError("The first parameter must be a valid string"); return v8::Local(); } + net::NetLogCaptureMode capture_mode = net::NetLogCaptureMode::kDefault; + uint64_t max_file_size = network::mojom::NetLogExporter::kUnlimitedFileSize; + + mate::Dictionary dict; + if (args->GetNext(&dict)) { + v8::Local capture_mode_v8; + if (dict.Get("captureMode", &capture_mode_v8)) { + if (!mate::ConvertFromV8(args->isolate(), capture_mode_v8, + &capture_mode)) { + args->ThrowError("Invalid value for captureMode"); + return v8::Local(); + } + } + v8::Local max_file_size_v8; + if (dict.Get("maxFileSize", &max_file_size_v8)) { + if (!mate::ConvertFromV8(args->isolate(), max_file_size_v8, + &max_file_size)) { + args->ThrowError("Invalid value for maxFileSize"); + return v8::Local(); + } + } + } + if (net_log_exporter_) { args->ThrowError("There is already a net log running"); return v8::Local(); @@ -90,11 +138,6 @@ v8::Local NetLog::StartLogging(mate::Arguments* args) { net_log_exporter_.set_connection_error_handler( base::BindOnce(&NetLog::OnConnectionError, base::Unretained(this))); - // TODO(deepak1556): Provide more flexibility to this module - // by allowing customizations on the capturing options. - auto capture_mode = net::NetLogCaptureMode::kDefault; - auto max_file_size = network::mojom::NetLogExporter::kUnlimitedFileSize; - base::PostTaskAndReplyWithResult( file_task_runner_.get(), FROM_HERE, base::BindOnce(OpenFileForWriting, log_path), diff --git a/shell/browser/api/atom_api_net_log.h b/shell/browser/api/atom_api_net_log.h index 8a3262a5d9d..421b65f5de0 100644 --- a/shell/browser/api/atom_api_net_log.h +++ b/shell/browser/api/atom_api_net_log.h @@ -31,7 +31,8 @@ class NetLog : public mate::TrackableObject { static void BuildPrototype(v8::Isolate* isolate, v8::Local prototype); - v8::Local StartLogging(mate::Arguments* args); + v8::Local StartLogging(base::FilePath log_path, + mate::Arguments* args); v8::Local StopLogging(mate::Arguments* args); bool IsCurrentlyLogging() const; diff --git a/spec-main/api-net-log-spec.js b/spec-main/api-net-log-spec.js index 5cefbab65a9..b35ca839826 100644 --- a/spec-main/api-net-log-spec.js +++ b/spec-main/api-net-log-spec.js @@ -5,7 +5,7 @@ const fs = require('fs') const os = require('os') const path = require('path') const ChildProcess = require('child_process') -const {session} = require('electron') +const {session, net} = require('electron') const appPath = path.join(__dirname, 'fixtures', 'api', 'net-log') const dumpFile = path.join(os.tmpdir(), 'net_log.json') const dumpFileDynamic = path.join(os.tmpdir(), 'net_log_dynamic.json') @@ -83,6 +83,43 @@ describe('netLog module', () => { expect(() => testNetLog().startLogging('')).to.throw() expect(() => testNetLog().startLogging(null)).to.throw() expect(() => testNetLog().startLogging([])).to.throw() + expect(() => testNetLog().startLogging('aoeu', {captureMode: 'aoeu'})).to.throw() + expect(() => testNetLog().startLogging('aoeu', {maxFileSize: null})).to.throw() + }) + + it('should include cookies when requested', async () => { + await testNetLog().startLogging(dumpFileDynamic, {captureMode: "includeSensitive"}) + const unique = require('uuid').v4() + await new Promise((resolve) => { + const req = net.request(server.url) + req.setHeader('Cookie', `foo=${unique}`) + req.on('response', (response) => { + response.on('data', () => {}) // https://github.com/electron/electron/issues/19214 + response.on('end', () => resolve()) + }) + req.end() + }) + await testNetLog().stopLogging() + expect(fs.existsSync(dumpFileDynamic)).to.be.true('dump file exists') + const dump = fs.readFileSync(dumpFileDynamic, 'utf8') + expect(dump).to.contain(`foo=${unique}`) + }) + + it('should include socket bytes when requested', async () => { + await testNetLog().startLogging(dumpFileDynamic, {captureMode: "everything"}) + const unique = require('uuid').v4() + await new Promise((resolve) => { + const req = net.request({method: 'POST', url: server.url}) + req.on('response', (response) => { + response.on('data', () => {}) // https://github.com/electron/electron/issues/19214 + response.on('end', () => resolve()) + }) + req.end(Buffer.from(unique)) + }) + await testNetLog().stopLogging() + expect(fs.existsSync(dumpFileDynamic)).to.be.true('dump file exists') + const dump = fs.readFileSync(dumpFileDynamic, 'utf8') + expect(JSON.parse(dump).events.some(x => x.params && x.params.bytes && Buffer.from(x.params.bytes, 'base64').includes(unique))).to.be.true('uuid present in dump') }) it('should begin and end logging automatically when --log-net-log is passed', done => {