| // 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 <utility> | 
 |  | 
 | #include "base/bind.h" | 
 | #include "base/debug/alias.h" | 
 | #include "base/logging.h" | 
 | #include "base/strings/string_number_conversions.h" | 
 | #include "base/strings/utf_string_conversions.h" | 
 | #include "base/time/time.h" | 
 | #include "base/values.h" | 
 | #include "net/base/net_errors.h" | 
 |  | 
 | namespace net { | 
 |  | 
 | namespace { | 
 |  | 
 | // Returns parameters for logging data transferred events. At a minimum includes | 
 | // the number of bytes transferred. If the capture mode allows logging byte | 
 | // contents and |byte_count| > 0, then will include the actual bytes. The | 
 | // bytes are hex-encoded, since base::StringValue only supports UTF-8. | 
 | std::unique_ptr<base::Value> BytesTransferredCallback( | 
 |     int byte_count, | 
 |     const char* bytes, | 
 |     NetLogCaptureMode capture_mode) { | 
 |   std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); | 
 |   dict->SetInteger("byte_count", byte_count); | 
 |   if (capture_mode.include_socket_bytes() && byte_count > 0) | 
 |     dict->SetString("hex_encoded_bytes", base::HexEncode(bytes, byte_count)); | 
 |   return std::move(dict); | 
 | } | 
 |  | 
 | std::unique_ptr<base::Value> SourceEventParametersCallback( | 
 |     const NetLog::Source source, | 
 |     NetLogCaptureMode /* capture_mode */) { | 
 |   if (!source.IsValid()) | 
 |     return std::unique_ptr<base::Value>(); | 
 |   std::unique_ptr<base::DictionaryValue> event_params( | 
 |       new base::DictionaryValue()); | 
 |   source.AddToEventParameters(event_params.get()); | 
 |   return std::move(event_params); | 
 | } | 
 |  | 
 | 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->SetString(name, base::Int64ToString(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); | 
 | } | 
 |  | 
 | }  // namespace | 
 |  | 
 | // LoadTimingInfo requires this be 0. | 
 | const uint32_t NetLog::Source::kInvalidId = 0; | 
 |  | 
 | NetLog::Source::Source() : type(SOURCE_NONE), id(kInvalidId) { | 
 | } | 
 |  | 
 | NetLog::Source::Source(SourceType type, uint32_t id) : type(type), id(id) {} | 
 |  | 
 | bool NetLog::Source::IsValid() const { | 
 |   return id != kInvalidId; | 
 | } | 
 |  | 
 | void NetLog::Source::AddToEventParameters( | 
 |     base::DictionaryValue* event_params) const { | 
 |   std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); | 
 |   dict->SetInteger("type", static_cast<int>(type)); | 
 |   dict->SetInteger("id", static_cast<int>(id)); | 
 |   event_params->Set("source_dependency", std::move(dict)); | 
 | } | 
 |  | 
 | NetLog::ParametersCallback NetLog::Source::ToEventParametersCallback() const { | 
 |   return base::Bind(&SourceEventParametersCallback, *this); | 
 | } | 
 |  | 
 | // static | 
 | bool NetLog::Source::FromEventParameters(base::Value* event_params, | 
 |                                          Source* source) { | 
 |   base::DictionaryValue* dict = NULL; | 
 |   base::DictionaryValue* source_dict = NULL; | 
 |   int source_id = -1; | 
 |   int source_type = NetLog::SOURCE_COUNT; | 
 |   if (!event_params || !event_params->GetAsDictionary(&dict) || | 
 |       !dict->GetDictionary("source_dependency", &source_dict) || | 
 |       !source_dict->GetInteger("id", &source_id) || | 
 |       !source_dict->GetInteger("type", &source_type)) { | 
 |     *source = Source(); | 
 |     return false; | 
 |   } | 
 |  | 
 |   DCHECK_GE(source_id, 0); | 
 |   DCHECK_LT(source_type, NetLog::SOURCE_COUNT); | 
 |   *source = Source(static_cast<SourceType>(source_type), source_id); | 
 |   return true; | 
 | } | 
 |  | 
 | base::Value* NetLog::Entry::ToValue() const { | 
 |   std::unique_ptr<base::DictionaryValue> entry_dict( | 
 |       new base::DictionaryValue()); | 
 |  | 
 |   entry_dict->SetString("time", TickCountToString(data_->time)); | 
 |  | 
 |   // Set the entry source. | 
 |   std::unique_ptr<base::DictionaryValue> source_dict( | 
 |       new base::DictionaryValue()); | 
 |   source_dict->SetInteger("id", data_->source.id); | 
 |   source_dict->SetInteger("type", static_cast<int>(data_->source.type)); | 
 |   entry_dict->Set("source", std::move(source_dict)); | 
 |  | 
 |   // Set the event info. | 
 |   entry_dict->SetInteger("type", static_cast<int>(data_->type)); | 
 |   entry_dict->SetInteger("phase", static_cast<int>(data_->phase)); | 
 |  | 
 |   // Set the event-specific parameters. | 
 |   if (data_->parameters_callback) { | 
 |     std::unique_ptr<base::Value> value( | 
 |         data_->parameters_callback->Run(capture_mode_)); | 
 |     if (value) | 
 |       entry_dict->Set("params", std::move(value)); | 
 |   } | 
 |  | 
 |   return entry_dict.release(); | 
 | } | 
 |  | 
 | std::unique_ptr<base::Value> NetLog::Entry::ParametersToValue() const { | 
 |   if (data_->parameters_callback) | 
 |     return data_->parameters_callback->Run(capture_mode_); | 
 |   return nullptr; | 
 | } | 
 |  | 
 | NetLog::EntryData::EntryData(EventType type, | 
 |                              Source source, | 
 |                              EventPhase phase, | 
 |                              base::TimeTicks time, | 
 |                              const ParametersCallback* parameters_callback) | 
 |     : type(type), | 
 |       source(source), | 
 |       phase(phase), | 
 |       time(time), | 
 |       parameters_callback(parameters_callback) { | 
 | } | 
 |  | 
 | NetLog::EntryData::~EntryData() { | 
 | } | 
 |  | 
 | NetLog::Entry::Entry(const EntryData* data, NetLogCaptureMode capture_mode) | 
 |     : data_(data), capture_mode_(capture_mode) { | 
 | } | 
 |  | 
 | NetLog::Entry::~Entry() { | 
 | } | 
 |  | 
 | 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 EntryData& entry_data) { | 
 |   OnAddEntry(Entry(&entry_data, capture_mode())); | 
 | } | 
 |  | 
 | NetLog::NetLog() : last_id_(0), is_capturing_(0) { | 
 | } | 
 |  | 
 | NetLog::~NetLog() { | 
 | } | 
 |  | 
 | void NetLog::AddGlobalEntry(EventType type) { | 
 |   AddEntry(type, Source(NetLog::SOURCE_NONE, NextID()), NetLog::PHASE_NONE, | 
 |            NULL); | 
 | } | 
 |  | 
 | void NetLog::AddGlobalEntry( | 
 |     EventType type, | 
 |     const NetLog::ParametersCallback& parameters_callback) { | 
 |   AddEntry(type, Source(NetLog::SOURCE_NONE, NextID()), NetLog::PHASE_NONE, | 
 |            ¶meters_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::DeprecatedAddObserver(NetLog::ThreadSafeObserver* observer, | 
 |                                    NetLogCaptureMode capture_mode) { | 
 |   base::AutoLock lock(lock_); | 
 |  | 
 |   DCHECK(!observer->net_log_); | 
 |   observers_.AddObserver(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(observers_.HasObserver(observer)); | 
 |   DCHECK_EQ(this, observer->net_log_); | 
 |   observer->capture_mode_ = capture_mode; | 
 | } | 
 |  | 
 | void NetLog::DeprecatedRemoveObserver(NetLog::ThreadSafeObserver* observer) { | 
 |   base::AutoLock lock(lock_); | 
 |  | 
 |   DCHECK(observers_.HasObserver(observer)); | 
 |   DCHECK_EQ(this, observer->net_log_); | 
 |   observers_.RemoveObserver(observer); | 
 |   observer->net_log_ = NULL; | 
 |   observer->capture_mode_ = NetLogCaptureMode(); | 
 |   UpdateIsCapturing(); | 
 | } | 
 |  | 
 | void NetLog::UpdateIsCapturing() { | 
 |   lock_.AssertAcquired(); | 
 |   base::subtle::NoBarrier_Store(&is_capturing_, | 
 |                                 observers_.might_have_observers() ? 1 : 0); | 
 | } | 
 |  | 
 | // static | 
 | std::string NetLog::TickCountToString(const base::TimeTicks& time) { | 
 |   int64_t delta_time = (time - base::TimeTicks()).InMilliseconds(); | 
 |   return base::Int64ToString(delta_time); | 
 | } | 
 |  | 
 | // static | 
 | const char* NetLog::EventTypeToString(EventType event) { | 
 |   switch (event) { | 
 | #define EVENT_TYPE(label) \ | 
 |   case TYPE_##label:      \ | 
 |     return #label; | 
 | #include "net/log/net_log_event_type_list.h" | 
 | #undef EVENT_TYPE | 
 |     default: | 
 |       NOTREACHED(); | 
 |       return NULL; | 
 |   } | 
 | } | 
 |  | 
 | // static | 
 | base::Value* NetLog::GetEventTypesAsValue() { | 
 |   std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); | 
 |   for (int i = 0; i < EVENT_COUNT; ++i) { | 
 |     dict->SetInteger(EventTypeToString(static_cast<EventType>(i)), i); | 
 |   } | 
 |   return dict.release(); | 
 | } | 
 |  | 
 | // static | 
 | const char* NetLog::SourceTypeToString(SourceType source) { | 
 |   switch (source) { | 
 | #define SOURCE_TYPE(label) \ | 
 |   case SOURCE_##label:     \ | 
 |     return #label; | 
 | #include "net/log/net_log_source_type_list.h" | 
 | #undef SOURCE_TYPE | 
 |     default: | 
 |       NOTREACHED(); | 
 |       return NULL; | 
 |   } | 
 | } | 
 |  | 
 | // static | 
 | base::Value* NetLog::GetSourceTypesAsValue() { | 
 |   std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); | 
 |   for (int i = 0; i < SOURCE_COUNT; ++i) { | 
 |     dict->SetInteger(SourceTypeToString(static_cast<SourceType>(i)), i); | 
 |   } | 
 |   return dict.release(); | 
 | } | 
 |  | 
 | // static | 
 | const char* NetLog::EventPhaseToString(EventPhase phase) { | 
 |   switch (phase) { | 
 |     case PHASE_BEGIN: | 
 |       return "PHASE_BEGIN"; | 
 |     case PHASE_END: | 
 |       return "PHASE_END"; | 
 |     case PHASE_NONE: | 
 |       return "PHASE_NONE"; | 
 |   } | 
 |   NOTREACHED(); | 
 |   return NULL; | 
 | } | 
 |  | 
 | // static | 
 | NetLog::ParametersCallback NetLog::BoolCallback(const char* name, bool value) { | 
 |   return base::Bind(&NetLogBoolCallback, name, value); | 
 | } | 
 |  | 
 | // static | 
 | NetLog::ParametersCallback NetLog::IntCallback(const char* name, int value) { | 
 |   return base::Bind(&NetLogIntCallback, name, value); | 
 | } | 
 |  | 
 | // static | 
 | NetLog::ParametersCallback NetLog::Int64Callback(const char* name, | 
 |                                                  int64_t value) { | 
 |   return base::Bind(&NetLogInt64Callback, name, value); | 
 | } | 
 |  | 
 | // static | 
 | NetLog::ParametersCallback NetLog::StringCallback(const char* name, | 
 |                                                   const std::string* value) { | 
 |   DCHECK(value); | 
 |   return base::Bind(&NetLogStringCallback, name, value); | 
 | } | 
 |  | 
 | // static | 
 | NetLog::ParametersCallback NetLog::StringCallback(const char* name, | 
 |                                                   const char* value) { | 
 |   DCHECK(value); | 
 |   return base::Bind(&NetLogCharStringCallback, name, value); | 
 | } | 
 |  | 
 | // static | 
 | NetLog::ParametersCallback NetLog::StringCallback(const char* name, | 
 |                                                   const base::string16* value) { | 
 |   DCHECK(value); | 
 |   return base::Bind(&NetLogString16Callback, name, value); | 
 | } | 
 |  | 
 | void NetLog::AddEntry(EventType type, | 
 |                       const Source& source, | 
 |                       EventPhase phase, | 
 |                       const NetLog::ParametersCallback* parameters_callback) { | 
 |   if (!IsCapturing()) | 
 |     return; | 
 |   EntryData entry_data(type, source, phase, base::TimeTicks::Now(), | 
 |                        parameters_callback); | 
 |  | 
 |   // Notify all of the log observers. | 
 |   base::AutoLock lock(lock_); | 
 |   FOR_EACH_OBSERVER(ThreadSafeObserver, observers_, OnAddEntryData(entry_data)); | 
 | } | 
 |  | 
 | BoundNetLog::~BoundNetLog() { | 
 |   liveness_ = DEAD; | 
 | } | 
 |  | 
 | void BoundNetLog::AddEntry(NetLog::EventType type, | 
 |                            NetLog::EventPhase phase) const { | 
 |   CrashIfInvalid(); | 
 |  | 
 |   if (!net_log_) | 
 |     return; | 
 |   net_log_->AddEntry(type, source_, phase, NULL); | 
 | } | 
 |  | 
 | void BoundNetLog::AddEntry( | 
 |     NetLog::EventType type, | 
 |     NetLog::EventPhase phase, | 
 |     const NetLog::ParametersCallback& get_parameters) const { | 
 |   CrashIfInvalid(); | 
 |  | 
 |   if (!net_log_) | 
 |     return; | 
 |   net_log_->AddEntry(type, source_, phase, &get_parameters); | 
 | } | 
 |  | 
 | void BoundNetLog::AddEvent(NetLog::EventType type) const { | 
 |   AddEntry(type, NetLog::PHASE_NONE); | 
 | } | 
 |  | 
 | void BoundNetLog::AddEvent( | 
 |     NetLog::EventType type, | 
 |     const NetLog::ParametersCallback& get_parameters) const { | 
 |   AddEntry(type, NetLog::PHASE_NONE, get_parameters); | 
 | } | 
 |  | 
 | void BoundNetLog::BeginEvent(NetLog::EventType type) const { | 
 |   AddEntry(type, NetLog::PHASE_BEGIN); | 
 | } | 
 |  | 
 | void BoundNetLog::BeginEvent( | 
 |     NetLog::EventType type, | 
 |     const NetLog::ParametersCallback& get_parameters) const { | 
 |   AddEntry(type, NetLog::PHASE_BEGIN, get_parameters); | 
 | } | 
 |  | 
 | void BoundNetLog::EndEvent(NetLog::EventType type) const { | 
 |   AddEntry(type, NetLog::PHASE_END); | 
 | } | 
 |  | 
 | void BoundNetLog::EndEvent( | 
 |     NetLog::EventType type, | 
 |     const NetLog::ParametersCallback& get_parameters) const { | 
 |   AddEntry(type, NetLog::PHASE_END, get_parameters); | 
 | } | 
 |  | 
 | void BoundNetLog::AddEventWithNetErrorCode(NetLog::EventType event_type, | 
 |                                            int net_error) const { | 
 |   DCHECK_NE(ERR_IO_PENDING, net_error); | 
 |   if (net_error >= 0) { | 
 |     AddEvent(event_type); | 
 |   } else { | 
 |     AddEvent(event_type, NetLog::IntCallback("net_error", net_error)); | 
 |   } | 
 | } | 
 |  | 
 | void BoundNetLog::EndEventWithNetErrorCode(NetLog::EventType event_type, | 
 |                                            int net_error) const { | 
 |   DCHECK_NE(ERR_IO_PENDING, net_error); | 
 |   if (net_error >= 0) { | 
 |     EndEvent(event_type); | 
 |   } else { | 
 |     EndEvent(event_type, NetLog::IntCallback("net_error", net_error)); | 
 |   } | 
 | } | 
 |  | 
 | void BoundNetLog::AddByteTransferEvent(NetLog::EventType event_type, | 
 |                                        int byte_count, | 
 |                                        const char* bytes) const { | 
 |   AddEvent(event_type, base::Bind(BytesTransferredCallback, byte_count, bytes)); | 
 | } | 
 |  | 
 | bool BoundNetLog::IsCapturing() const { | 
 |   CrashIfInvalid(); | 
 |   return net_log_ && net_log_->IsCapturing(); | 
 | } | 
 |  | 
 | // static | 
 | BoundNetLog BoundNetLog::Make(NetLog* net_log, NetLog::SourceType source_type) { | 
 |   if (!net_log) | 
 |     return BoundNetLog(); | 
 |  | 
 |   NetLog::Source source(source_type, net_log->NextID()); | 
 |   return BoundNetLog(source, net_log); | 
 | } | 
 |  | 
 | void BoundNetLog::CrashIfInvalid() const { | 
 |   Liveness liveness = liveness_; | 
 |  | 
 |   if (liveness == ALIVE) | 
 |     return; | 
 |  | 
 |   base::debug::Alias(&liveness); | 
 |   CHECK_EQ(ALIVE, liveness); | 
 | } | 
 |  | 
 | }  // namespace net |