1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "net/base/net_log_logger.h"
6
7#include <stdio.h>
8
9#include "base/json/json_writer.h"
10#include "base/logging.h"
11#include "base/memory/scoped_ptr.h"
12#include "base/strings/string_number_conversions.h"
13#include "base/values.h"
14#include "net/base/address_family.h"
15#include "net/base/load_states.h"
16#include "net/base/net_errors.h"
17#include "net/quic/quic_protocol.h"
18#include "net/quic/quic_utils.h"
19
20namespace {
21
22struct StringToConstant {
23  const char* name;
24  const int constant;
25};
26
27const StringToConstant kCertStatusFlags[] = {
28#define CERT_STATUS_FLAG(label, value) { #label, value },
29#include "net/cert/cert_status_flags_list.h"
30#undef CERT_STATUS_FLAG
31};
32
33const StringToConstant kLoadFlags[] = {
34#define LOAD_FLAG(label, value) { #label, value },
35#include "net/base/load_flags_list.h"
36#undef LOAD_FLAG
37};
38
39const StringToConstant kLoadStateTable[] = {
40#define LOAD_STATE(label) { # label, net::LOAD_STATE_ ## label },
41#include "net/base/load_states_list.h"
42#undef LOAD_STATE
43};
44
45const short kNetErrors[] = {
46#define NET_ERROR(label, value) value,
47#include "net/base/net_error_list.h"
48#undef NET_ERROR
49};
50
51}  // namespace
52
53namespace net {
54
55// This should be incremented when significant changes are made that will
56// invalidate the old loading code.
57static const int kLogFormatVersion = 1;
58
59NetLogLogger::NetLogLogger(FILE* file, const base::Value& constants)
60    : file_(file), log_level_(NetLog::LOG_ALL_BUT_BYTES), added_events_(false) {
61  DCHECK(file);
62
63  // Write constants to the output file.  This allows loading files that have
64  // different source and event types, as they may be added and removed
65  // between Chrome versions.
66  std::string json;
67  base::JSONWriter::Write(&constants, &json);
68  fprintf(file_.get(), "{\"constants\": %s,\n", json.c_str());
69  fprintf(file_.get(), "\"events\": [\n");
70}
71
72NetLogLogger::~NetLogLogger() {
73  if (file_.get())
74    fprintf(file_.get(), "]}");
75}
76
77void NetLogLogger::set_log_level(net::NetLog::LogLevel log_level) {
78  DCHECK(!net_log());
79  log_level_ = log_level;
80}
81
82void NetLogLogger::StartObserving(net::NetLog* net_log) {
83  net_log->AddThreadSafeObserver(this, log_level_);
84}
85
86void NetLogLogger::StopObserving() {
87  net_log()->RemoveThreadSafeObserver(this);
88}
89
90void NetLogLogger::OnAddEntry(const net::NetLog::Entry& entry) {
91  // Add a comma and newline for every event but the first.  Newlines are needed
92  // so can load partial log files by just ignoring the last line.  For this to
93  // work, lines cannot be pretty printed.
94  scoped_ptr<base::Value> value(entry.ToValue());
95  std::string json;
96  base::JSONWriter::Write(value.get(), &json);
97  fprintf(file_.get(), "%s%s",
98          (added_events_ ? ",\n" : ""),
99          json.c_str());
100  added_events_ = true;
101}
102
103base::DictionaryValue* NetLogLogger::GetConstants() {
104  base::DictionaryValue* constants_dict = new base::DictionaryValue();
105
106  // Version of the file format.
107  constants_dict->SetInteger("logFormatVersion", kLogFormatVersion);
108
109  // Add a dictionary with information on the relationship between event type
110  // enums and their symbolic names.
111  constants_dict->Set("logEventTypes", net::NetLog::GetEventTypesAsValue());
112
113  // Add a dictionary with information about the relationship between CertStatus
114  // flags and their symbolic names.
115  {
116    base::DictionaryValue* dict = new base::DictionaryValue();
117
118    for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kCertStatusFlags); i++)
119      dict->SetInteger(kCertStatusFlags[i].name, kCertStatusFlags[i].constant);
120
121    constants_dict->Set("certStatusFlag", dict);
122  }
123
124  // Add a dictionary with information about the relationship between load flag
125  // enums and their symbolic names.
126  {
127    base::DictionaryValue* dict = new base::DictionaryValue();
128
129    for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kLoadFlags); i++)
130      dict->SetInteger(kLoadFlags[i].name, kLoadFlags[i].constant);
131
132    constants_dict->Set("loadFlag", dict);
133  }
134
135  // Add a dictionary with information about the relationship between load state
136  // enums and their symbolic names.
137  {
138    base::DictionaryValue* dict = new base::DictionaryValue();
139
140    for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kLoadStateTable); i++)
141      dict->SetInteger(kLoadStateTable[i].name, kLoadStateTable[i].constant);
142
143    constants_dict->Set("loadState", dict);
144  }
145
146  // Add information on the relationship between net error codes and their
147  // symbolic names.
148  {
149    base::DictionaryValue* dict = new base::DictionaryValue();
150
151    for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kNetErrors); i++)
152      dict->SetInteger(ErrorToShortString(kNetErrors[i]), kNetErrors[i]);
153
154    constants_dict->Set("netError", dict);
155  }
156
157  // Add information on the relationship between QUIC error codes and their
158  // symbolic names.
159  {
160    base::DictionaryValue* dict = new base::DictionaryValue();
161
162    for (net::QuicErrorCode error = net::QUIC_NO_ERROR;
163         error < net::QUIC_LAST_ERROR;
164         error = static_cast<net::QuicErrorCode>(error + 1)) {
165      dict->SetInteger(net::QuicUtils::ErrorToString(error),
166                       static_cast<int>(error));
167    }
168
169    constants_dict->Set("quicError", dict);
170  }
171
172  // Add information on the relationship between QUIC RST_STREAM error codes
173  // and their symbolic names.
174  {
175    base::DictionaryValue* dict = new base::DictionaryValue();
176
177    for (net::QuicRstStreamErrorCode error = net::QUIC_STREAM_NO_ERROR;
178         error < net::QUIC_STREAM_LAST_ERROR;
179         error = static_cast<net::QuicRstStreamErrorCode>(error + 1)) {
180      dict->SetInteger(net::QuicUtils::StreamErrorToString(error),
181                       static_cast<int>(error));
182    }
183
184    constants_dict->Set("quicRstStreamError", dict);
185  }
186
187  // Information about the relationship between event phase enums and their
188  // symbolic names.
189  {
190    base::DictionaryValue* dict = new base::DictionaryValue();
191
192    dict->SetInteger("PHASE_BEGIN", net::NetLog::PHASE_BEGIN);
193    dict->SetInteger("PHASE_END", net::NetLog::PHASE_END);
194    dict->SetInteger("PHASE_NONE", net::NetLog::PHASE_NONE);
195
196    constants_dict->Set("logEventPhase", dict);
197  }
198
199  // Information about the relationship between source type enums and
200  // their symbolic names.
201  constants_dict->Set("logSourceType", net::NetLog::GetSourceTypesAsValue());
202
203  // Information about the relationship between LogLevel enums and their
204  // symbolic names.
205  {
206    base::DictionaryValue* dict = new base::DictionaryValue();
207
208    dict->SetInteger("LOG_ALL", net::NetLog::LOG_ALL);
209    dict->SetInteger("LOG_ALL_BUT_BYTES", net::NetLog::LOG_ALL_BUT_BYTES);
210    dict->SetInteger("LOG_STRIP_PRIVATE_DATA",
211                     net::NetLog::LOG_STRIP_PRIVATE_DATA);
212
213    constants_dict->Set("logLevelType", dict);
214  }
215
216  // Information about the relationship between address family enums and
217  // their symbolic names.
218  {
219    base::DictionaryValue* dict = new base::DictionaryValue();
220
221    dict->SetInteger("ADDRESS_FAMILY_UNSPECIFIED",
222                     net::ADDRESS_FAMILY_UNSPECIFIED);
223    dict->SetInteger("ADDRESS_FAMILY_IPV4",
224                     net::ADDRESS_FAMILY_IPV4);
225    dict->SetInteger("ADDRESS_FAMILY_IPV6",
226                     net::ADDRESS_FAMILY_IPV6);
227
228    constants_dict->Set("addressFamily", dict);
229  }
230
231  // Information about how the "time ticks" values we have given it relate to
232  // actual system times. (We used time ticks throughout since they are stable
233  // across system clock changes).
234  {
235    int64 cur_time_ms = (base::Time::Now() - base::Time()).InMilliseconds();
236
237    int64 cur_time_ticks_ms =
238        (base::TimeTicks::Now() - base::TimeTicks()).InMilliseconds();
239
240    // If we add this number to a time tick value, it gives the timestamp.
241    int64 tick_to_time_ms = cur_time_ms - cur_time_ticks_ms;
242
243    // Chrome on all platforms stores times using the Windows epoch
244    // (Jan 1 1601), but the javascript wants a unix epoch.
245    // TODO(eroman): Getting the timestamp relative to the unix epoch should
246    //               be part of the time library.
247    const int64 kUnixEpochMs = 11644473600000LL;
248    int64 tick_to_unix_time_ms = tick_to_time_ms - kUnixEpochMs;
249
250    // Pass it as a string, since it may be too large to fit in an integer.
251    constants_dict->SetString("timeTickOffset",
252                              base::Int64ToString(tick_to_unix_time_ms));
253  }
254
255  // "clientInfo" key is required for some NetLogLogger log readers.
256  // Provide a default empty value for compatibility.
257  constants_dict->Set("clientInfo", new base::DictionaryValue());
258
259  return constants_dict;
260}
261
262}  // namespace net
263