summaryrefslogtreecommitdiff
path: root/chromium/components/net_log/net_export_file_writer.h
blob: 92c615849aea5182b728ab3b839257b7693da97b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
// 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 <memory>
#include <string>

#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::DictionaryValue& 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<void(const base::FilePath&)>;
  using DirectoryGetter = base::RepeatingCallback<bool(base::FilePath*)>;

  // 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
  std::unique_ptr<base::DictionaryValue> 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<base::TaskRunner> 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<network::mojom::NetLogExporter> net_log_exporter_;

  // List of StateObservers to notify on state changes.
  base::ObserverList<StateObserver, true>::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<NetExportFileWriter> weak_ptr_factory_{this};
};

}  // namespace net_log

#endif  // COMPONENTS_NET_LOG_NET_EXPORT_FILE_WRITER_H_