devtools_netlog_observer.cc revision 201ade2fbba22bfb27ae029f4d23fca6ded109a0
1// Copyright (c) 2010 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 "chrome/browser/io_thread.h"
9#include "chrome/common/resource_response.h"
10#include "net/base/load_flags.h"
11#include "net/http/http_net_log_params.h"
12#include "net/http/http_response_headers.h"
13#include "net/url_request/url_request.h"
14#include "net/url_request/url_request_netlog_params.h"
15#include "webkit/glue/resource_loader_bridge.h"
16
17const size_t kMaxNumEntries = 1000;
18
19DevToolsNetLogObserver* DevToolsNetLogObserver::instance_ = NULL;
20
21DevToolsNetLogObserver::DevToolsNetLogObserver(ChromeNetLog* chrome_net_log)
22    : ChromeNetLog::Observer(net::NetLog::LOG_ALL_BUT_BYTES),
23      chrome_net_log_(chrome_net_log) {
24  chrome_net_log_->AddObserver(this);
25}
26
27DevToolsNetLogObserver::~DevToolsNetLogObserver() {
28  chrome_net_log_->RemoveObserver(this);
29}
30
31DevToolsNetLogObserver::ResourceInfo*
32DevToolsNetLogObserver::GetResourceInfo(uint32 id) {
33  RequestToInfoMap::iterator it = request_to_info_.find(id);
34  if (it != request_to_info_.end())
35    return it->second;
36  return NULL;
37}
38
39void DevToolsNetLogObserver::OnAddEntry(net::NetLog::EventType type,
40                                        const base::TimeTicks& time,
41                                        const net::NetLog::Source& source,
42                                        net::NetLog::EventPhase phase,
43                                        net::NetLog::EventParameters* params) {
44  if (type == net::NetLog::TYPE_URL_REQUEST_START_JOB) {
45    if (phase != net::NetLog::PHASE_BEGIN)
46      return;
47    int load_flags = static_cast<URLRequestStartEventParameters*>(params)->
48        load_flags();
49    if (!(load_flags & net::LOAD_REPORT_RAW_HEADERS))
50      return;
51    if (request_to_info_.size() > kMaxNumEntries) {
52      LOG(WARNING) << "The raw headers observer url request count has grown "
53                      "larger than expected, resetting";
54      request_to_info_.clear();
55    }
56    scoped_refptr<ResourceInfo> new_record(new ResourceInfo());
57    // We may encounter multiple PHASE_BEGIN for same resource in case of
58    // redirect -- if so, replace the old record to avoid keeping headers
59    // from different requests.
60    std::pair<RequestToInfoMap::iterator, bool> inserted =
61        request_to_info_.insert(std::make_pair(source.id, new_record));
62    if (!inserted.second)
63      inserted.first->second = new_record;
64    return;
65  }
66  if (type == net::NetLog::TYPE_REQUEST_ALIVE &&
67      phase == net::NetLog::PHASE_END) {
68    request_to_info_.erase(source.id);
69    return;
70  }
71  if (type != net::NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST_HEADERS &&
72      type != net::NetLog::TYPE_HTTP_TRANSACTION_READ_RESPONSE_HEADERS)
73    return;
74
75  ResourceInfo* info = GetResourceInfo(source.id);
76  if (!info)
77    return;
78
79  switch (type) {
80    case net::NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST_HEADERS: {
81      const net::HttpRequestHeaders &request_headers =
82          static_cast<net::NetLogHttpRequestParameter*>(params)->GetHeaders();
83      for (net::HttpRequestHeaders::Iterator it(request_headers);
84           it.GetNext();) {
85        info->request_headers.push_back(std::make_pair(it.name(),
86                                                       it.value()));
87      }
88      break;
89    }
90    case net::NetLog::TYPE_HTTP_TRANSACTION_READ_RESPONSE_HEADERS: {
91      const net::HttpResponseHeaders& response_headers =
92          static_cast<net::NetLogHttpResponseParameter*>(params)->GetHeaders();
93      info->http_status_code = response_headers.response_code();
94      info->http_status_text = response_headers.GetStatusText();
95      std::string name, value;
96      for (void* it = NULL;
97           response_headers.EnumerateHeaderLines(&it, &name, &value); ) {
98        info->response_headers.push_back(std::make_pair(name, value));
99      }
100      break;
101    }
102    default:
103      break;
104  }
105}
106
107void DevToolsNetLogObserver::Attach(IOThread* io_thread) {
108  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
109  DCHECK(!instance_);
110
111  instance_ = new DevToolsNetLogObserver(io_thread->globals()->net_log.get());
112}
113
114void DevToolsNetLogObserver::Detach() {
115  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
116  DCHECK(instance_);
117
118  delete instance_;
119  instance_ = NULL;
120}
121
122DevToolsNetLogObserver* DevToolsNetLogObserver::GetInstance() {
123  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
124
125  return instance_;
126}
127
128// static
129void DevToolsNetLogObserver::PopulateResponseInfo(URLRequest* request,
130                                                  ResourceResponse* response) {
131  if (!(request->load_flags() & net::LOAD_REPORT_RAW_HEADERS))
132    return;
133
134  uint32 source_id = request->net_log().source().id;
135  DevToolsNetLogObserver* dev_tools_net_log_observer =
136      DevToolsNetLogObserver::GetInstance();
137  if (!dev_tools_net_log_observer)
138    return;
139  response->response_head.devtools_info =
140      dev_tools_net_log_observer->GetResourceInfo(source_id);
141}
142