| OLD | NEW |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 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 #ifndef COMPONENTS_NET_LOG_NET_LOG_FILE_WRITER_H_ | 5 #ifndef COMPONENTS_NET_LOG_NET_LOG_FILE_WRITER_H_ |
| 6 #define COMPONENTS_NET_LOG_NET_LOG_FILE_WRITER_H_ | 6 #define COMPONENTS_NET_LOG_NET_LOG_FILE_WRITER_H_ |
| 7 | 7 |
| 8 #include <memory> | 8 #include <memory> |
| 9 #include <string> | 9 #include <string> |
| 10 | 10 |
| 11 #include "base/callback.h" |
| 11 #include "base/command_line.h" | 12 #include "base/command_line.h" |
| 12 #include "base/files/file_path.h" | 13 #include "base/files/file_path.h" |
| 13 #include "base/gtest_prod_util.h" | 14 #include "base/gtest_prod_util.h" |
| 14 #include "base/macros.h" | 15 #include "base/macros.h" |
| 16 #include "base/memory/ref_counted.h" |
| 17 #include "base/memory/weak_ptr.h" |
| 15 #include "base/threading/thread_checker.h" | 18 #include "base/threading/thread_checker.h" |
| 19 #include "net/log/net_log_capture_mode.h" |
| 16 | 20 |
| 17 namespace base { | 21 namespace base { |
| 18 class DictionaryValue; | 22 class DictionaryValue; |
| 23 class SingleThreadTaskRunner; |
| 24 class Value; |
| 19 } | 25 } |
| 20 | 26 |
| 21 namespace net { | 27 namespace net { |
| 22 class NetLogCaptureMode; | 28 class FileNetLogObserver; |
| 23 class WriteToFileNetLogObserver; | 29 class URLRequestContextGetter; |
| 24 } | 30 } |
| 25 | 31 |
| 26 namespace net_log { | 32 namespace net_log { |
| 27 | 33 |
| 28 class ChromeNetLog; | 34 class ChromeNetLog; |
| 29 | 35 |
| 30 // NetLogFileWriter logs all the NetLog entries into a specified file. | 36 // NetLogFileWriter is used exclusively as a support class for net-export. |
| 37 // It's a singleton that acts as the interface to all NetExportMessageHandlers |
| 38 // which can tell it to start or stop logging in response to user actions from |
| 39 // net-export UIs. Because it's a singleton, the logging state can be shared |
| 40 // between multiple instances of the net-export UI. Internally, it manages an |
| 41 // instance of net::FileNetLogObserver and handles the attaching/detaching of it |
| 42 // to the ChromeNetLog. This class is used by the iOS and non-iOS |
| 43 // implementations of net-export. |
| 31 // | 44 // |
| 32 // NetLogFileWriter maintains the current logging state (state_) and log file | 45 // NetLogFileWriter maintains the current logging state (using the members |
| 33 // type (log_type_) of the logging into a chrome-net-export-log.json file. | 46 // (|state_|, |log_exists_|, |log_capture_mode_known_|, |log_capture_mode_|). |
| 47 // Its three main commands are StartNetLog(), StopNetLog() and GetState(). These |
| 48 // are the only functions that may cause NetLogFileWriter to change state. |
| 49 // Also, NetLogFileWriter is lazily initialized. A portion of the initialization |
| 50 // needs to run on the |file_task_runner_|. |
| 34 // | 51 // |
| 35 // The following are the possible states | 52 // This class is created and destroyed on the UI thread, and all public entry |
| 36 // a) Only Start is allowed (STATE_NOT_LOGGING, LOG_TYPE_NONE). | 53 // points are to be called on the UI thread. Internally, the class may run some |
| 37 // b) Only Stop is allowed (STATE_LOGGING). | 54 // code on the |file_task_runner_| and |net_task_runner_|. |
| 38 // c) Either Send or Start is allowed (STATE_NOT_LOGGING, anything but | |
| 39 // LOG_TYPE_NONE). | |
| 40 // | |
| 41 // This is created/destroyed on the main thread, but all other function calls | |
| 42 // occur on a background thread. | |
| 43 // | |
| 44 // This relies on the UI thread outlasting all other threads for thread safety. | |
| 45 class NetLogFileWriter { | 55 class NetLogFileWriter { |
| 46 public: | 56 public: |
| 47 // This enum lists the UI button commands it could receive. | 57 // The three main commands StartNetLog(), StopNetLog(), and GetState() and the |
| 48 enum Command { | 58 // getter GetFilePathToCompletedLog() all accept a callback param which is |
| 49 DO_START_LOG_BYTES, // Call StartNetLog logging all bytes received. | 59 // used to notify the caller of the results of that function. For all these |
| 50 DO_START, // Call StartNetLog. | 60 // commands, the callback will always be executed even if the command ends up |
| 51 DO_START_STRIP_PRIVATE_DATA, // Call StartNetLog stripping private data. | 61 // being a no-op or if some failure occurs. |
| 52 DO_STOP, // Call StopNetLog. | |
| 53 }; | |
| 54 | 62 |
| 55 virtual ~NetLogFileWriter(); | 63 using StateCallback = |
| 64 base::Callback<void(std::unique_ptr<base::DictionaryValue>)>; |
| 56 | 65 |
| 57 // Accepts the button command and executes it. | 66 using FilePathCallback = base::Callback<void(const base::FilePath&)>; |
| 58 void ProcessCommand(Command command); | |
| 59 | 67 |
| 60 // Returns true and the path to the file. If there is no file to | 68 using DirectoryGetter = base::Callback<bool(base::FilePath*)>; |
| 61 // send, then it returns false. It also returns false when actively logging to | |
| 62 // the file. | |
| 63 bool GetFilePath(base::FilePath* path); | |
| 64 | 69 |
| 65 // Creates a Value summary of the state of the NetLogFileWriter. The caller is | 70 ~NetLogFileWriter(); |
| 66 // responsible for deleting the returned value. | |
| 67 base::DictionaryValue* GetState(); | |
| 68 | 71 |
| 69 // Updates |log_path_| to the |custom_path|. | 72 // Starts collecting NetLog data into the file at |log_path|. If |log_path| is |
| 70 void SetUpNetExportLogPath(const base::FilePath& custom_path); | 73 // empty, the default log path is used. It is a no-op if NetLogFileWriter is |
| 74 // already collecting data into a file, and |capture_mode| is ignored. |
| 75 // TODO(mmenke): That's rather weird behavior, think about improving it. |
| 76 // |
| 77 // If NetLogFileWriter is not initialized, StartNetLog() will trigger |
| 78 // initialization. |
| 79 // |
| 80 // |state_callback| will be executed at the end of StartNetLog() |
| 81 // asynchronously. If StartNetLog() is called while initialization is already |
| 82 // in progress, |state_callback| will be called after the ongoing |
| 83 // initialization finishes. |
| 84 void StartNetLog(const base::FilePath& log_path, |
| 85 net::NetLogCaptureMode capture_mode, |
| 86 const StateCallback& state_callback); |
| 87 |
| 88 // Stops collecting NetLog data into the file. It is a no-op if |
| 89 // NetLogFileWriter is currently not logging. |
| 90 // |
| 91 // |polled_data| is a JSON dictionary that will be appended to the end of the |
| 92 // log; it's for adding additional info to the log that aren't events. |
| 93 // If |context_getter| is not null, then StopNetLog() will automatically |
| 94 // append net info (from net::GetNetInfo() retrieved using |context_getter|) |
| 95 // to |polled_data|. |
| 96 // |
| 97 // |state_callback| will be executed at the end of StopNetLog() |
| 98 // asynchronously, explicitly after the log file is complete. |
| 99 void StopNetLog(std::unique_ptr<base::DictionaryValue> polled_data, |
| 100 scoped_refptr<net::URLRequestContextGetter> context_getter, |
| 101 const StateCallback& state_callback); |
| 102 |
| 103 // Creates a Value summary of the state of the NetLogFileWriter and calls |
| 104 // |state_callback| asynchronously with that Value as the param. |
| 105 // |
| 106 // If NetLogFileWriter is not initialized, GetState() will trigger |
| 107 // initialization, and |state_callback| will be called after initialization |
| 108 // finishes. |
| 109 void GetState(const StateCallback& state_callback); |
| 110 |
| 111 // Gets the log filepath. |path_callback| will be used to notify the caller |
| 112 // when the filepath is retrieved. |path_callback| will be executed with an |
| 113 // empty filepath if any of the following occurs: |
| 114 // (1) The NetLogFileWriter is not initialized. |
| 115 // (2) The log file does not exist. |
| 116 // (3) The NetLogFileWriter is currently logging. |
| 117 // (4) The log file's permissions could not be set to all. |
| 118 // |
| 119 // |path_callback| will be executed at the end of GetFilePathToCompletedLog() |
| 120 // asynchronously. |
| 121 void GetFilePathToCompletedLog(const FilePathCallback& path_callback) const; |
| 122 |
| 123 // Sets the task runners used by NetLogFileWriter for doing file I/O and |
| 124 // network I/O respectively. This must be called prior to using the |
| 125 // NetLogFileWriter. The task runners must not be changed once set. However, |
| 126 // calling this function again with the same parameters is OK. |
| 127 void SetTaskRunners( |
| 128 scoped_refptr<base::SingleThreadTaskRunner> file_task_runner, |
| 129 scoped_refptr<base::SingleThreadTaskRunner> net_task_runner); |
| 130 |
| 131 // Converts to/from the string representation of a capture mode used by |
| 132 // net_export.js. |
| 133 static std::string CaptureModeToString(net::NetLogCaptureMode capture_mode); |
| 134 static net::NetLogCaptureMode CaptureModeFromString( |
| 135 const std::string& capture_mode_string); |
| 136 |
| 137 // Overrides the getter used to retrieve the default log base directory during |
| 138 // initialization. Should only be used by unit tests. |
| 139 void SetDefaultLogBaseDirectoryGetterForTest(const DirectoryGetter& getter); |
| 71 | 140 |
| 72 protected: | 141 protected: |
| 73 // Constructs a NetLogFileWriter. Only one instance is created in browser | 142 // Constructs a NetLogFileWriter. Only one instance is created in browser |
| 74 // process. | 143 // process. |
| 75 NetLogFileWriter(ChromeNetLog* chrome_net_log, | 144 NetLogFileWriter(ChromeNetLog* chrome_net_log, |
| 76 const base::CommandLine::StringType& command_line_string, | 145 const base::CommandLine::StringType& command_line_string, |
| 77 const std::string& channel_string); | 146 const std::string& channel_string); |
| 78 | 147 |
| 79 // Returns path name to base::GetTempDir() directory. Returns false if | |
| 80 // base::GetTempDir() fails. | |
| 81 virtual bool GetNetExportLogBaseDirectory(base::FilePath* path) const; | |
| 82 | |
| 83 private: | 148 private: |
| 84 friend class ChromeNetLog; | 149 friend class ChromeNetLog; |
| 85 friend class NetLogFileWriterTest; | 150 friend class NetLogFileWriterTest; |
| 86 | 151 |
| 87 // Allow tests to access our innards for testing purposes. | 152 // The possible logging states of NetLogFileWriter. |
| 88 FRIEND_TEST_ALL_PREFIXES(NetLogFileWriterTest, EnsureInitFailure); | |
| 89 FRIEND_TEST_ALL_PREFIXES(NetLogFileWriterTest, EnsureInitAllowStart); | |
| 90 FRIEND_TEST_ALL_PREFIXES(NetLogFileWriterTest, EnsureInitAllowStartOrSend); | |
| 91 FRIEND_TEST_ALL_PREFIXES(NetLogFileWriterTest, ProcessCommandDoStartAndStop); | |
| 92 FRIEND_TEST_ALL_PREFIXES(NetLogFileWriterTest, DoStartClearsFile); | |
| 93 FRIEND_TEST_ALL_PREFIXES(NetLogFileWriterTest, CheckAddEvent); | |
| 94 FRIEND_TEST_ALL_PREFIXES(NetLogFileWriterTest, CheckAddEventWithCustomPath); | |
| 95 | |
| 96 // This enum lists the possible state NetLogFileWriter could be in. It is used | |
| 97 // to enable/disable "Start", "Stop" and "Send" (email) UI actions. | |
| 98 enum State { | 153 enum State { |
| 99 STATE_UNINITIALIZED, | 154 STATE_UNINITIALIZED, |
| 155 // Currently in the process of initializing. |
| 156 STATE_INITIALIZING, |
| 100 // Not currently logging to file. | 157 // Not currently logging to file. |
| 101 STATE_NOT_LOGGING, | 158 STATE_NOT_LOGGING, |
| 102 // Currently logging to file. | 159 // Currently logging to file. |
| 103 STATE_LOGGING, | 160 STATE_LOGGING, |
| 161 // Currently in the process of stopping the log. |
| 162 STATE_STOPPING_LOG, |
| 104 }; | 163 }; |
| 105 | 164 |
| 106 // The type of the current log file on disk. | 165 // Struct used to store the results of SetUpDefaultLogPath() which will be |
| 107 enum LogType { | 166 // passed to InitStateThenCallback(). |
| 108 // There is no current log file. | 167 struct DefaultLogPathResults { |
| 109 LOG_TYPE_NONE, | 168 bool default_log_path_success; |
| 110 // The file predates this session. May or may not have private data. | 169 base::FilePath default_log_path; |
| 111 // TODO(davidben): This state is kind of silly. | 170 bool log_exists; |
| 112 LOG_TYPE_UNKNOWN, | |
| 113 // The log includes raw bytes. | |
| 114 LOG_TYPE_LOG_BYTES, | |
| 115 // The file includes all data. | |
| 116 LOG_TYPE_NORMAL, | |
| 117 // The file has credentials and cookies stripped. | |
| 118 LOG_TYPE_STRIP_PRIVATE_DATA, | |
| 119 }; | 171 }; |
| 120 | 172 |
| 121 // Returns the NetLog::CaptureMode corresponding to a LogType. | 173 // Helper function used by StartNetLog() and GetState(). If NetLogFileWriter |
| 122 static net::NetLogCaptureMode GetCaptureModeForLogType(LogType log_type); | 174 // is uninitialized, this function will attempt initialization and then |
| 175 // run its callbacks. |
| 176 // |
| 177 // |after_successful_init_callback| is only called after a successful |
| 178 // initialization has completed (triggered by this call or a previous call). |
| 179 // This callback is used to do actual work outside of initialization. |
| 180 // |
| 181 // |state_callback| is called at the end asynchronously no matter what. It's |
| 182 // used to notify the caller of the state of NetLogFileWriter after |
| 183 // everything's done. If EnsureInitThenRun() is called while a previously- |
| 184 // triggered initialization is still ongoing, |state_callback| will wait |
| 185 // until after the ongoing intialization finishes before running. |
| 186 void EnsureInitThenRun(const base::Closure& after_successful_init_callback, |
| 187 const StateCallback& state_callback); |
| 123 | 188 |
| 124 // Initializes the |state_| to STATE_NOT_LOGGING and |log_type_| to | 189 // Contains file-related initialization tasks. Will run on the file task |
| 125 // LOG_TYPE_NONE (if there is no file from earlier run) or | 190 // runner. |
| 126 // LOG_TYPE_UNKNOWN (if there is a file from earlier run). Returns | 191 static DefaultLogPathResults SetUpDefaultLogPath( |
| 127 // false if initialization of |log_path_| fails. | 192 const DirectoryGetter& default_log_base_directory_getter); |
| 128 bool EnsureInit(); | |
| 129 | 193 |
| 130 // Start collecting NetLog data into chrome-net-export-log.json file in | 194 // Will initialize NetLogFileWriter's state variables using the result of |
| 131 // a directory, using the specified capture mode. It is a no-op if we are | 195 // SetUpDefaultLogPath(). |
| 132 // already collecting data into a file, and |capture_mode| is ignored. | 196 // |
| 133 // ignored. | 197 // |after_successful_init_callback| is only executed if |
| 134 // TODO(mmenke): That's rather weird behavior, think about improving it. | 198 // |set_up_default_log_path_results| indicates SetUpDefaultLogPath() |
| 135 void StartNetLog(LogType log_type); | 199 // succeeded. |
| 200 // |
| 201 // |state_callback| is executed at the end synchronously in all cases. |
| 202 void SetStateAfterSetUpDefaultLogPathThenRun( |
| 203 const base::Closure& after_successful_init_callback, |
| 204 const StateCallback& state_callback, |
| 205 const DefaultLogPathResults& set_up_default_log_path_results); |
| 136 | 206 |
| 137 // Stop collecting NetLog data into the file. It is a no-op if we | 207 // Gets the state, then runs |state_callback| synchronously. |
| 138 // are not collecting data into a file. | 208 void RunStateCallback(const StateCallback& state_callback) const; |
| 139 void StopNetLog(); | |
| 140 | 209 |
| 141 // Updates |log_path_| to be the base::FilePath to use for log files, which | 210 // Asychronously calls RunStateCallback(). |
| 142 // will be inside the base::GetTempDir() directory. Returns false if | 211 void RunStateCallbackAsync(const StateCallback& state_callback); |
| 143 // base::GetTempDir() fails, or unable to create a subdirectory for logging | |
| 144 // within that directory. | |
| 145 bool SetUpDefaultNetExportLogPath(); | |
| 146 | 212 |
| 147 // Returns true if a file exists at |log_path_|. | 213 // Called internally by StartNetLog(). Does the actual work needed by |
| 148 bool NetExportLogExists() const; | 214 // StartNetLog() outside of initialization and running the state callback. |
| 215 void StartNetLogAfterInitialized(const base::FilePath& log_path, |
| 216 net::NetLogCaptureMode capture_mode); |
| 217 |
| 218 // Called internally by StopNetLog(). Does the actual work needed by |
| 219 // StopNetLog() outside of retrieving the net info. |
| 220 void StopNetLogAfterAddNetInfo( |
| 221 const StateCallback& state_callback, |
| 222 std::unique_ptr<base::DictionaryValue> polled_data); |
| 223 |
| 224 // Contains tasks to be done after |write_to_file_observer_| has completely |
| 225 // stopped writing. |
| 226 void ResetObserverThenSetStateNotLogging(const StateCallback& state_callback); |
| 227 |
| 228 std::unique_ptr<base::DictionaryValue> GetState() const; |
| 229 |
| 230 // All members are accessed solely from the main thread (the thread that |
| 231 // |thread_checker_| is bound to). |
| 149 | 232 |
| 150 base::ThreadChecker thread_checker_; | 233 base::ThreadChecker thread_checker_; |
| 151 | 234 |
| 152 // Helper function for unit tests. | 235 // Task runners for file-specific and net-specific tasks that must run on a |
| 153 State state() const { return state_; } | 236 // file or net thread. |
| 154 LogType log_type() const { return log_type_; } | 237 scoped_refptr<base::SingleThreadTaskRunner> file_task_runner_; |
| 238 scoped_refptr<base::SingleThreadTaskRunner> net_task_runner_; |
| 155 | 239 |
| 156 State state_; // Current state of NetLogFileWriter. | 240 State state_; // Current logging state of NetLogFileWriter. |
| 157 LogType log_type_; // Type of current log file on disk. | 241 |
| 242 bool log_exists_; // Whether or not the log exists on disk. |
| 243 bool log_capture_mode_known_; |
| 244 net::NetLogCaptureMode log_capture_mode_; |
| 158 | 245 |
| 159 base::FilePath log_path_; // base::FilePath to the NetLog file. | 246 base::FilePath log_path_; // base::FilePath to the NetLog file. |
| 160 | 247 |
| 161 // |write_to_file_observer_| watches the NetLog event stream, and | 248 // |write_to_file_observer_| watches the NetLog event stream, and |
| 162 // sends all entries to the file created in StartNetLog(). | 249 // sends all entries to the file created in StartNetLog(). |
| 163 std::unique_ptr<net::WriteToFileNetLogObserver> write_to_file_observer_; | 250 std::unique_ptr<net::FileNetLogObserver> write_to_file_observer_; |
| 164 | 251 |
| 165 // The |chrome_net_log_| is owned by the browser process, cached here to avoid | 252 // The |chrome_net_log_| is owned by the browser process, cached here to avoid |
| 166 // using global (g_browser_process). | 253 // using global (g_browser_process). |
| 167 ChromeNetLog* chrome_net_log_; | 254 ChromeNetLog* chrome_net_log_; |
| 168 | 255 |
| 169 const base::CommandLine::StringType command_line_string_; | 256 const base::CommandLine::StringType command_line_string_; |
| 170 const std::string channel_string_; | 257 const std::string channel_string_; |
| 171 | 258 |
| 259 // Used by unit tests to override the default log base directory retrieved |
| 260 // during initialization. This getter is initialized to base::GetTempDir(). |
| 261 DirectoryGetter default_log_base_directory_getter_; |
| 262 |
| 263 base::WeakPtrFactory<NetLogFileWriter> weak_ptr_factory_; |
| 264 |
| 172 DISALLOW_COPY_AND_ASSIGN(NetLogFileWriter); | 265 DISALLOW_COPY_AND_ASSIGN(NetLogFileWriter); |
| 173 }; | 266 }; |
| 174 | 267 |
| 175 } // namespace net_log | 268 } // namespace net_log |
| 176 | 269 |
| 177 #endif // COMPONENTS_NET_LOG_NET_LOG_FILE_WRITER_H_ | 270 #endif // COMPONENTS_NET_LOG_NET_LOG_FILE_WRITER_H_ |
| OLD | NEW |