Home | History | Annotate | Download | only in debugger
      1 // Copyright (c) 2011 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 "chrome/browser/debugger/devtools_netlog_observer.h"
      6 
      7 #include "base/string_util.h"
      8 #include "base/values.h"
      9 #include "chrome/browser/io_thread.h"
     10 #include "content/common/resource_response.h"
     11 #include "net/base/load_flags.h"
     12 #include "net/http/http_net_log_params.h"
     13 #include "net/http/http_response_headers.h"
     14 #include "net/url_request/url_request.h"
     15 #include "net/url_request/url_request_netlog_params.h"
     16 #include "webkit/glue/resource_loader_bridge.h"
     17 
     18 const size_t kMaxNumEntries = 1000;
     19 
     20 DevToolsNetLogObserver* DevToolsNetLogObserver::instance_ = NULL;
     21 
     22 DevToolsNetLogObserver::DevToolsNetLogObserver(ChromeNetLog* chrome_net_log)
     23     : ChromeNetLog::ThreadSafeObserver(net::NetLog::LOG_ALL_BUT_BYTES),
     24       chrome_net_log_(chrome_net_log) {
     25   chrome_net_log_->AddObserver(this);
     26 }
     27 
     28 DevToolsNetLogObserver::~DevToolsNetLogObserver() {
     29   chrome_net_log_->RemoveObserver(this);
     30 }
     31 
     32 DevToolsNetLogObserver::ResourceInfo*
     33 DevToolsNetLogObserver::GetResourceInfo(uint32 id) {
     34   RequestToInfoMap::iterator it = request_to_info_.find(id);
     35   if (it != request_to_info_.end())
     36     return it->second;
     37   return NULL;
     38 }
     39 
     40 void DevToolsNetLogObserver::OnAddEntry(net::NetLog::EventType type,
     41                                         const base::TimeTicks& time,
     42                                         const net::NetLog::Source& source,
     43                                         net::NetLog::EventPhase phase,
     44                                         net::NetLog::EventParameters* params) {
     45   // The events that the Observer is interested in only occur on the IO thread.
     46   if (!BrowserThread::CurrentlyOn(BrowserThread::IO))
     47     return;
     48 
     49   // The events that the Observer is interested in only occur on the IO thread.
     50   if (!BrowserThread::CurrentlyOn(BrowserThread::IO))
     51     return;
     52   if (source.type == net::NetLog::SOURCE_URL_REQUEST)
     53     OnAddURLRequestEntry(type, time, source, phase, params);
     54   else if (source.type == net::NetLog::SOURCE_HTTP_STREAM_JOB)
     55     OnAddHTTPStreamJobEntry(type, time, source, phase, params);
     56   else if (source.type == net::NetLog::SOURCE_SOCKET)
     57     OnAddSocketEntry(type, time, source, phase, params);
     58 }
     59 
     60 void DevToolsNetLogObserver::OnAddURLRequestEntry(
     61     net::NetLog::EventType type,
     62     const base::TimeTicks& time,
     63     const net::NetLog::Source& source,
     64     net::NetLog::EventPhase phase,
     65     net::NetLog::EventParameters* params) {
     66   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
     67 
     68   bool is_begin = phase == net::NetLog::PHASE_BEGIN;
     69   bool is_end = phase == net::NetLog::PHASE_END;
     70 
     71   if (type == net::NetLog::TYPE_URL_REQUEST_START_JOB) {
     72     if (is_begin) {
     73       int load_flags = static_cast<
     74           net::URLRequestStartEventParameters*>(params)->load_flags();
     75       if (!(load_flags & net::LOAD_REPORT_RAW_HEADERS))
     76         return;
     77 
     78       if (request_to_info_.size() > kMaxNumEntries) {
     79         LOG(WARNING) << "The raw headers observer url request count has grown "
     80                         "larger than expected, resetting";
     81         request_to_info_.clear();
     82       }
     83 
     84       request_to_info_[source.id] = new ResourceInfo();
     85 
     86       if (request_to_encoded_data_length_.size() > kMaxNumEntries) {
     87         LOG(WARNING) << "The encoded data length observer url request count "
     88                         "has grown larger than expected, resetting";
     89         request_to_encoded_data_length_.clear();
     90       }
     91 
     92       request_to_encoded_data_length_[source.id] = 0;
     93     }
     94     return;
     95   } else if (type == net::NetLog::TYPE_REQUEST_ALIVE) {
     96     // Cleanup records based on the TYPE_REQUEST_ALIVE entry.
     97     if (is_end) {
     98       request_to_info_.erase(source.id);
     99       request_to_encoded_data_length_.erase(source.id);
    100     }
    101     return;
    102   }
    103 
    104   ResourceInfo* info = GetResourceInfo(source.id);
    105   if (!info)
    106     return;
    107 
    108   switch (type) {
    109     case net::NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST_HEADERS: {
    110       const net::HttpRequestHeaders &request_headers =
    111           static_cast<net::NetLogHttpRequestParameter*>(params)->GetHeaders();
    112       for (net::HttpRequestHeaders::Iterator it(request_headers);
    113            it.GetNext();) {
    114         info->request_headers.push_back(std::make_pair(it.name(),
    115                                                        it.value()));
    116       }
    117       break;
    118     }
    119     case net::NetLog::TYPE_HTTP_TRANSACTION_READ_RESPONSE_HEADERS: {
    120       const net::HttpResponseHeaders& response_headers =
    121           static_cast<net::NetLogHttpResponseParameter*>(params)->GetHeaders();
    122       info->http_status_code = response_headers.response_code();
    123       info->http_status_text = response_headers.GetStatusText();
    124       std::string name, value;
    125       for (void* it = NULL;
    126            response_headers.EnumerateHeaderLines(&it, &name, &value); ) {
    127         info->response_headers.push_back(std::make_pair(name, value));
    128       }
    129       break;
    130     }
    131     case net::NetLog::TYPE_HTTP_STREAM_REQUEST_BOUND_TO_JOB: {
    132       uint32 http_stream_job_id = static_cast<net::NetLogSourceParameter*>(
    133           params)->value().id;
    134       HTTPStreamJobToSocketMap::iterator it =
    135           http_stream_job_to_socket_.find(http_stream_job_id);
    136       if (it == http_stream_job_to_socket_.end())
    137         return;
    138       uint32 socket_id = it->second;
    139 
    140       if (socket_to_request_.size() > kMaxNumEntries) {
    141         LOG(WARNING) << "The url request observer socket count has grown "
    142                         "larger than expected, resetting";
    143         socket_to_request_.clear();
    144       }
    145 
    146       socket_to_request_[socket_id] = source.id;
    147       http_stream_job_to_socket_.erase(http_stream_job_id);
    148       break;
    149     }
    150     default:
    151       break;
    152   }
    153 }
    154 
    155 void DevToolsNetLogObserver::OnAddHTTPStreamJobEntry(
    156     net::NetLog::EventType type,
    157     const base::TimeTicks& time,
    158     const net::NetLog::Source& source,
    159     net::NetLog::EventPhase phase,
    160     net::NetLog::EventParameters* params) {
    161   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    162 
    163   if (type == net::NetLog::TYPE_SOCKET_POOL_BOUND_TO_SOCKET) {
    164     uint32 socket_id = static_cast<net::NetLogSourceParameter*>(
    165       params)->value().id;
    166 
    167     // Prevents us from passively growing the memory unbounded in
    168     // case something went wrong. Should not happen.
    169     if (http_stream_job_to_socket_.size() > kMaxNumEntries) {
    170       LOG(WARNING) << "The load timing observer http stream job count "
    171                       "has grown larger than expected, resetting";
    172       http_stream_job_to_socket_.clear();
    173     }
    174     http_stream_job_to_socket_[source.id] = socket_id;
    175   }
    176 }
    177 
    178 void DevToolsNetLogObserver::OnAddSocketEntry(
    179     net::NetLog::EventType type,
    180     const base::TimeTicks& time,
    181     const net::NetLog::Source& source,
    182     net::NetLog::EventPhase phase,
    183     net::NetLog::EventParameters* params) {
    184   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    185 
    186   bool is_end = phase == net::NetLog::PHASE_END;
    187 
    188   SocketToRequestMap::iterator it = socket_to_request_.find(source.id);
    189   if (it == socket_to_request_.end())
    190     return;
    191   uint32 request_id = it->second;
    192 
    193   if (type == net::NetLog::TYPE_SOCKET_IN_USE) {
    194     if (is_end)
    195       socket_to_request_.erase(source.id);
    196     return;
    197   }
    198 
    199   RequestToEncodedDataLengthMap::iterator encoded_data_length_it =
    200       request_to_encoded_data_length_.find(request_id);
    201   if (encoded_data_length_it == request_to_encoded_data_length_.end())
    202     return;
    203 
    204   if (net::NetLog::TYPE_SOCKET_BYTES_RECEIVED == type) {
    205     int byte_count = 0;
    206     Value* value = params->ToValue();
    207     if (!value->IsType(Value::TYPE_DICTIONARY))
    208       return;
    209 
    210     DictionaryValue* dValue = static_cast<DictionaryValue*>(value);
    211     if (!dValue->GetInteger("byte_count", &byte_count))
    212       return;
    213 
    214     encoded_data_length_it->second += byte_count;
    215   }
    216 }
    217 
    218 void DevToolsNetLogObserver::Attach(IOThread* io_thread) {
    219   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    220   DCHECK(!instance_);
    221 
    222   instance_ = new DevToolsNetLogObserver(io_thread->net_log());
    223 }
    224 
    225 void DevToolsNetLogObserver::Detach() {
    226   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    227   DCHECK(instance_);
    228 
    229   delete instance_;
    230   instance_ = NULL;
    231 }
    232 
    233 DevToolsNetLogObserver* DevToolsNetLogObserver::GetInstance() {
    234   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    235 
    236   return instance_;
    237 }
    238 
    239 // static
    240 void DevToolsNetLogObserver::PopulateResponseInfo(net::URLRequest* request,
    241                                                   ResourceResponse* response) {
    242   if (!(request->load_flags() & net::LOAD_REPORT_RAW_HEADERS))
    243     return;
    244 
    245   uint32 source_id = request->net_log().source().id;
    246   DevToolsNetLogObserver* dev_tools_net_log_observer =
    247       DevToolsNetLogObserver::GetInstance();
    248   if (dev_tools_net_log_observer == NULL)
    249     return;
    250   response->response_head.devtools_info =
    251       dev_tools_net_log_observer->GetResourceInfo(source_id);
    252 }
    253 
    254 // static
    255 int DevToolsNetLogObserver::GetAndResetEncodedDataLength(
    256     net::URLRequest* request) {
    257   if (!(request->load_flags() & net::LOAD_REPORT_RAW_HEADERS))
    258     return -1;
    259 
    260   uint32 source_id = request->net_log().source().id;
    261   DevToolsNetLogObserver* dev_tools_net_log_observer =
    262       DevToolsNetLogObserver::GetInstance();
    263   if (dev_tools_net_log_observer == NULL)
    264     return -1;
    265 
    266   RequestToEncodedDataLengthMap::iterator it =
    267       dev_tools_net_log_observer->request_to_encoded_data_length_.find(
    268           source_id);
    269   if (it == dev_tools_net_log_observer->request_to_encoded_data_length_.end())
    270     return -1;
    271   int encoded_data_length = it->second;
    272   it->second = 0;
    273   return encoded_data_length;
    274 }
    275