blob: 95b42e7f8be4a9dc71905a39597e4d9124288028 [file] [log] [blame]
// Copyright (c) 2012 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.
#include "net/log/net_log.h"
#include <algorithm>
#include <memory>
#include <utility>
#include "base/base64.h"
#include "base/bind.h"
#include "base/callback.h"
#include "base/logging.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "net/base/escape.h"
namespace net {
namespace {
std::unique_ptr<base::Value> NetLogBoolCallback(
const char* name,
bool value,
NetLogCaptureMode /* capture_mode */) {
std::unique_ptr<base::DictionaryValue> event_params(
new base::DictionaryValue());
event_params->SetBoolean(name, value);
return std::move(event_params);
}
std::unique_ptr<base::Value> NetLogIntCallback(
const char* name,
int value,
NetLogCaptureMode /* capture_mode */) {
std::unique_ptr<base::DictionaryValue> event_params(
new base::DictionaryValue());
event_params->SetInteger(name, value);
return std::move(event_params);
}
std::unique_ptr<base::Value> NetLogInt64Callback(
const char* name,
int64_t value,
NetLogCaptureMode /* capture_mode */) {
std::unique_ptr<base::DictionaryValue> event_params(
new base::DictionaryValue());
event_params->SetKey(name, NetLogNumberValue(value));
return std::move(event_params);
}
std::unique_ptr<base::Value> NetLogStringCallback(
const char* name,
const std::string* value,
NetLogCaptureMode /* capture_mode */) {
std::unique_ptr<base::DictionaryValue> event_params(
new base::DictionaryValue());
event_params->SetString(name, *value);
return std::move(event_params);
}
std::unique_ptr<base::Value> NetLogCharStringCallback(
const char* name,
const char* value,
NetLogCaptureMode /* capture_mode */) {
std::unique_ptr<base::DictionaryValue> event_params(
new base::DictionaryValue());
event_params->SetString(name, value);
return std::move(event_params);
}
std::unique_ptr<base::Value> NetLogString16Callback(
const char* name,
const base::string16* value,
NetLogCaptureMode /* capture_mode */) {
std::unique_ptr<base::DictionaryValue> event_params(
new base::DictionaryValue());
event_params->SetString(name, *value);
return std::move(event_params);
}
// IEEE 64-bit doubles have a 52-bit mantissa, and can therefore represent
// 53-bits worth of precision (see also documentation for JavaScript's
// Number.MAX_SAFE_INTEGER for more discussion on this).
//
// If the number can be represented with an int or double use that. Otherwise
// fallback to encoding it as a string.
template <typename T>
base::Value NetLogNumberValueHelper(T num) {
// Fits in a (32-bit) int: [-2^31, 2^31 - 1]
if ((!std::is_signed<T>::value || (num >= static_cast<T>(-2147483648))) &&
(num <= static_cast<T>(2147483647))) {
return base::Value(static_cast<int>(num));
}
// Fits in a double: (-2^53, 2^53)
if ((!std::is_signed<T>::value ||
(num >= static_cast<T>(-9007199254740991))) &&
(num <= static_cast<T>(9007199254740991))) {
return base::Value(static_cast<double>(num));
}
// Otherwise format as a string.
return base::Value(base::NumberToString(num));
}
} // namespace
NetLog::ThreadSafeObserver::ThreadSafeObserver() : net_log_(NULL) {
}
NetLog::ThreadSafeObserver::~ThreadSafeObserver() {
// Make sure we aren't watching a NetLog on destruction. Because the NetLog
// may pass events to each observer on multiple threads, we cannot safely
// stop watching a NetLog automatically from a parent class.
DCHECK(!net_log_);
}
NetLogCaptureMode NetLog::ThreadSafeObserver::capture_mode() const {
DCHECK(net_log_);
return capture_mode_;
}
NetLog* NetLog::ThreadSafeObserver::net_log() const {
return net_log_;
}
void NetLog::ThreadSafeObserver::OnAddEntryData(
const NetLogEntryData& entry_data) {
OnAddEntry(NetLogEntry(&entry_data, capture_mode()));
}
NetLog::NetLog() : last_id_(0), is_capturing_(0) {
}
NetLog::~NetLog() = default;
void NetLog::AddGlobalEntry(NetLogEventType type) {
AddEntry(type, NetLogSource(NetLogSourceType::NONE, NextID()),
NetLogEventPhase::NONE, NULL);
}
void NetLog::AddGlobalEntry(
NetLogEventType type,
const NetLogParametersCallback& parameters_callback) {
AddEntry(type, NetLogSource(NetLogSourceType::NONE, NextID()),
NetLogEventPhase::NONE, &parameters_callback);
}
uint32_t NetLog::NextID() {
return base::subtle::NoBarrier_AtomicIncrement(&last_id_, 1);
}
bool NetLog::IsCapturing() const {
return base::subtle::NoBarrier_Load(&is_capturing_) != 0;
}
void NetLog::AddObserver(NetLog::ThreadSafeObserver* observer,
NetLogCaptureMode capture_mode) {
base::AutoLock lock(lock_);
DCHECK(!observer->net_log_);
DCHECK(!HasObserver(observer));
DCHECK_LT(observers_.size(), 20u); // Performance sanity check.
observers_.push_back(observer);
observer->net_log_ = this;
observer->capture_mode_ = capture_mode;
UpdateIsCapturing();
}
void NetLog::SetObserverCaptureMode(NetLog::ThreadSafeObserver* observer,
NetLogCaptureMode capture_mode) {
base::AutoLock lock(lock_);
DCHECK(HasObserver(observer));
DCHECK_EQ(this, observer->net_log_);
observer->capture_mode_ = capture_mode;
}
void NetLog::RemoveObserver(NetLog::ThreadSafeObserver* observer) {
base::AutoLock lock(lock_);
DCHECK_EQ(this, observer->net_log_);
auto it = std::find(observers_.begin(), observers_.end(), observer);
DCHECK(it != observers_.end());
observers_.erase(it);
observer->net_log_ = NULL;
observer->capture_mode_ = NetLogCaptureMode();
UpdateIsCapturing();
}
void NetLog::UpdateIsCapturing() {
lock_.AssertAcquired();
base::subtle::NoBarrier_Store(&is_capturing_, observers_.size() ? 1 : 0);
}
bool NetLog::HasObserver(ThreadSafeObserver* observer) {
lock_.AssertAcquired();
return base::ContainsValue(observers_, observer);
}
// static
std::string NetLog::TickCountToString(const base::TimeTicks& time) {
int64_t delta_time = (time - base::TimeTicks()).InMilliseconds();
// TODO(https://crbug.com/915391): Use NetLogNumberValue().
return base::NumberToString(delta_time);
}
// static
const char* NetLog::EventTypeToString(NetLogEventType event) {
switch (event) {
#define EVENT_TYPE(label) \
case NetLogEventType::label: \
return #label;
#include "net/log/net_log_event_type_list.h"
#undef EVENT_TYPE
default:
NOTREACHED();
return NULL;
}
}
// static
std::unique_ptr<base::Value> NetLog::GetEventTypesAsValue() {
auto dict = std::make_unique<base::DictionaryValue>();
for (int i = 0; i < static_cast<int>(NetLogEventType::COUNT); ++i) {
dict->SetInteger(EventTypeToString(static_cast<NetLogEventType>(i)), i);
}
return std::move(dict);
}
// static
const char* NetLog::SourceTypeToString(NetLogSourceType source) {
switch (source) {
#define SOURCE_TYPE(label) \
case NetLogSourceType::label: \
return #label;
#include "net/log/net_log_source_type_list.h"
#undef SOURCE_TYPE
default:
NOTREACHED();
return NULL;
}
}
// static
std::unique_ptr<base::Value> NetLog::GetSourceTypesAsValue() {
auto dict = std::make_unique<base::DictionaryValue>();
for (int i = 0; i < static_cast<int>(NetLogSourceType::COUNT); ++i) {
dict->SetInteger(SourceTypeToString(static_cast<NetLogSourceType>(i)), i);
}
return std::move(dict);
}
// static
const char* NetLog::EventPhaseToString(NetLogEventPhase phase) {
switch (phase) {
case NetLogEventPhase::BEGIN:
return "PHASE_BEGIN";
case NetLogEventPhase::END:
return "PHASE_END";
case NetLogEventPhase::NONE:
return "PHASE_NONE";
}
NOTREACHED();
return NULL;
}
// static
NetLogParametersCallback NetLog::BoolCallback(const char* name, bool value) {
return base::Bind(&NetLogBoolCallback, name, value);
}
// static
NetLogParametersCallback NetLog::IntCallback(const char* name, int value) {
return base::Bind(&NetLogIntCallback, name, value);
}
// static
NetLogParametersCallback NetLog::Int64Callback(const char* name,
int64_t value) {
return base::Bind(&NetLogInt64Callback, name, value);
}
// static
NetLogParametersCallback NetLog::StringCallback(const char* name,
const std::string* value) {
DCHECK(value);
return base::Bind(&NetLogStringCallback, name, value);
}
// static
NetLogParametersCallback NetLog::StringCallback(const char* name,
const char* value) {
DCHECK(value);
return base::Bind(&NetLogCharStringCallback, name, value);
}
// static
NetLogParametersCallback NetLog::StringCallback(const char* name,
const base::string16* value) {
DCHECK(value);
return base::Bind(&NetLogString16Callback, name, value);
}
void NetLog::AddEntry(NetLogEventType type,
const NetLogSource& source,
NetLogEventPhase phase,
const NetLogParametersCallback* parameters_callback) {
if (!IsCapturing())
return;
NetLogEntryData entry_data(type, source, phase, base::TimeTicks::Now(),
parameters_callback);
// Notify all of the log observers.
base::AutoLock lock(lock_);
for (auto* observer : observers_)
observer->OnAddEntryData(entry_data);
}
base::Value NetLogStringValue(base::StringPiece raw) {
// The common case is that |raw| is ASCII. Represent this directly.
if (base::IsStringASCII(raw))
return base::Value(raw);
// For everything else (including valid UTF-8) percent-escape |raw|, and add a
// prefix that "tags" the value as being a percent-escaped representation.
//
// Note that the sequence E2 80 8B is U+200B (zero-width space) in UTF-8. It
// is added so the escaped string is not itself also ASCII (otherwise there
// would be ambiguity for consumers as to when the value needs to be
// unescaped).
return base::Value("%ESCAPED:\xE2\x80\x8B " + EscapeNonASCIIAndPercent(raw));
}
base::Value NetLogBinaryValue(const void* bytes, size_t length) {
std::string b64;
Base64Encode(base::StringPiece(reinterpret_cast<const char*>(bytes), length),
&b64);
return base::Value(std::move(b64));
}
base::Value NetLogNumberValue(int64_t num) {
return NetLogNumberValueHelper(num);
}
base::Value NetLogNumberValue(uint64_t num) {
return NetLogNumberValueHelper(num);
}
} // namespace net