// Copyright (c) 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef COMPONENTS_NET_LOG_NET_EXPORT_FILE_WRITER_H_ #define COMPONENTS_NET_LOG_NET_EXPORT_FILE_WRITER_H_ #include #include #include "base/callback.h" #include "base/command_line.h" #include "base/files/file.h" #include "base/files/file_path.h" #include "base/gtest_prod_util.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" #include "base/observer_list.h" #include "base/threading/thread_checker.h" #include "base/values.h" #include "mojo/public/cpp/bindings/remote.h" #include "net/log/net_log_capture_mode.h" #include "services/network/public/mojom/net_log.mojom.h" #include "services/network/public/mojom/network_service.mojom.h" namespace base { class TaskRunner; } // namespace base namespace network { namespace mojom { class NetworkContext; } } // namespace network namespace net_log { // NetExportFileWriter is used exclusively as a support class for // chrome://net-export/. There's a single instance created globally that acts as // the interface to all NetExportMessageHandlers which can tell it to start or // stop logging in response to user actions from chrome://net-export/ UIs. // Because there's only one instance, the logging state can be shared between // multiple instances of the chrome://net-export/ UI. Internally, it manages a // pipe to an instance of network::NetLogExporter and handles the // attaching/detaching of it to the NetLog. This class is used by the iOS and // non-iOS implementations of chrome://net-export/. // // NetExportFileWriter maintains the current logging state using the members // |state_|, |log_exists_|, |log_capture_mode_known_|, |log_capture_mode_|. // Its three main commands are Initialize(), StartNetLog(), and StopNetLog(). // These are the only functions that may cause NetExportFileWriter to change // state. Initialize() must be called before NetExportFileWriter can process any // other commands. A portion of the initialization needs to run on the // |file_task_runner_|. // // This class is created and destroyed on the UI thread, and all public entry // points are to be called on the UI thread. Internally, the class may run some // code on the |file_task_runner_|. class NetExportFileWriter { public: // Special value meaning "can use an unlimited number of bytes". static constexpr uint64_t kNoLimit = network::mojom::NetLogExporter::kUnlimitedFileSize; // The observer interface to be implemented by code that wishes to be notified // of NetExportFileWriter's state changes. class StateObserver { public: virtual void OnNewState(const base::Value::Dict& state) = 0; }; // Struct used to store the results of setting up the default log directory // and log path. struct DefaultLogPathResults { bool default_log_path_success; base::FilePath default_log_path; bool log_exists; }; using FilePathCallback = base::OnceCallback; using DirectoryGetter = base::RepeatingCallback; // Constructs a NetExportFileWriter. Only one instance is created in browser // process. NetExportFileWriter(); NetExportFileWriter(const NetExportFileWriter&) = delete; NetExportFileWriter& operator=(const NetExportFileWriter&) = delete; ~NetExportFileWriter(); // Attaches a StateObserver. |observer| will be notified of state changes to // NetExportFileWriter. State changes may occur in response to Initiailze(), // StartNetLog(), or StopNetLog(). StateObserver::OnNewState() will be called // asynchronously relative to the command that caused the state change. // |observer| must remain alive until RemoveObserver() is called. void AddObserver(StateObserver* observer); // Detaches a StateObserver. void RemoveObserver(StateObserver* observer); // Initializes NetExportFileWriter if not initialized. Calling this function // again is OK. void Initialize(); // Starts collecting NetLog data into the file at |log_path|. If |log_path| is // empty, the default log path is used. If NetExportFileWriter is already // logging, this is a no-op and |capture_mode| is ignored. // // |max_file_size| places a bound on how large the log file can grow. To make // it grow unboundedly pass kNoLimit. // // |network_context| will be used to append net info (from net::GetInfo()) // at end of logging once StopNetLog is called. void StartNetLog(const base::FilePath& log_path, net::NetLogCaptureMode capture_mode, uint64_t max_file_size, const base::CommandLine::StringType& command_line_string, const std::string& channel_string, network::mojom::NetworkContext* network_context); // Stops collecting NetLog data into the file. It is a no-op if // NetExportFileWriter is currently not logging. // // |polled_data| is a JSON dictionary that will be appended to the end of the // log; it's for adding additional info to the log that aren't events. void StopNetLog(base::Value::Dict polled_data = base::Value::Dict()); // Creates a DictionaryValue summary of the state of the NetExportFileWriter base::Value::Dict GetState() const; // Gets the log filepath. |path_callback| will be used to notify the caller // when the filepath is retrieved. |path_callback| will be executed with an // empty filepath if any of the following occurs: // (1) The NetExportFileWriter is not initialized. // (2) The log file does not exist. // (3) The NetExportFileWriter is currently logging. // // |path_callback| will be executed at the end of GetFilePathToCompletedLog() // asynchronously. void GetFilePathToCompletedLog(FilePathCallback path_callback) const; // Converts to/from the string representation of a capture mode used by // net_export.js. static std::string CaptureModeToString(net::NetLogCaptureMode capture_mode); static net::NetLogCaptureMode CaptureModeFromString( const std::string& capture_mode_string); // Overrides the getter used to retrieve the default log base directory during // initialization. Should only be used by unit tests. void SetDefaultLogBaseDirectoryGetterForTest(const DirectoryGetter& getter); private: friend class NetExportFileWriterTest; // The possible logging states of NetExportFileWriter. enum State { STATE_UNINITIALIZED, // Currently in the process of initializing. STATE_INITIALIZING, // Not currently logging to file. STATE_NOT_LOGGING, // Currently in the process of starting the log. STATE_STARTING_LOG, // Currently logging to file. STATE_LOGGING, // Currently in the process of stopping the log. STATE_STOPPING_LOG, }; void NotifyStateObservers(); // Posts NotifyStateObservers() to the current thread. void NotifyStateObserversAsync(); // Called internally by Initialize(). Will initialize NetExportFileWriter's // state variables after the default log directory is set up and the default // log path is determined on the |file_task_runner_|. void SetStateAfterSetUpDefaultLogPath( const DefaultLogPathResults& set_up_default_log_path_results); // Called internally by StartNetLog(). Contains tasks to be done to start // logging after the output file has been created. void StartNetLogAfterCreateFile(net::NetLogCaptureMode capture_mode, uint64_t max_file_size, base::Value::Dict custom_constants, base::File log_file); void OnStartResult(net::NetLogCaptureMode capture_mode, int result); void OnStopResult(int result); void OnConnectionError(); // Contains tasks to be done after |net_log_exporter_| has completely // stopped writing. void ResetExporterThenSetStateNotLogging(); // Creates a new file for writing at |path|, trying to overwrite any existing // file. Called on |file_task_runner_|. static base::File CreateOutputFile(base::FilePath path); // All members are accessed solely from the main thread (the thread that // |thread_checker_| is bound to). base::ThreadChecker thread_checker_; // Task runners for file-specific and net-specific tasks that must run on a // file or net task runner. scoped_refptr file_task_runner_; State state_; // Current logging state of NetExportFileWriter. bool log_exists_; // Whether or not a log file exists on disk. bool log_capture_mode_known_; net::NetLogCaptureMode log_capture_mode_; base::FilePath log_path_; // base::FilePath to the NetLog file. // Used to ask the network service to do the actual exporting. mojo::Remote net_log_exporter_; // List of StateObservers to notify on state changes. base::ObserverList::Unchecked state_observer_list_; // Used by unit tests to override the default log base directory retrieved // during initialization. This getter is initialized to base::GetTempDir(). DirectoryGetter default_log_base_dir_getter_; base::WeakPtrFactory weak_ptr_factory_{this}; }; } // namespace net_log #endif // COMPONENTS_NET_LOG_NET_EXPORT_FILE_WRITER_H_