Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / content / browser / devtools / devtools_netlog_observer.cc
1 // Copyright (c) 2012 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 "content/browser/devtools/devtools_netlog_observer.h"
6
7 #include "base/strings/string_util.h"
8 #include "base/values.h"
9 #include "content/public/browser/browser_thread.h"
10 #include "content/public/browser/content_browser_client.h"
11 #include "content/public/common/resource_response.h"
12 #include "net/base/load_flags.h"
13 #include "net/http/http_response_headers.h"
14 #include "net/http/http_util.h"
15 #include "net/spdy/spdy_header_block.h"
16 #include "net/url_request/url_request.h"
17 #include "net/url_request/url_request_netlog_params.h"
18
19 namespace content {
20 const size_t kMaxNumEntries = 1000;
21
22 DevToolsNetLogObserver* DevToolsNetLogObserver::instance_ = NULL;
23
24 DevToolsNetLogObserver::DevToolsNetLogObserver() {
25 }
26
27 DevToolsNetLogObserver::~DevToolsNetLogObserver() {
28 }
29
30 DevToolsNetLogObserver::ResourceInfo*
31 DevToolsNetLogObserver::GetResourceInfo(uint32 id) {
32   RequestToInfoMap::iterator it = request_to_info_.find(id);
33   if (it != request_to_info_.end())
34     return it->second.get();
35   return NULL;
36 }
37
38 void DevToolsNetLogObserver::OnAddEntry(const net::NetLog::Entry& entry) {
39   // The events that the Observer is interested in only occur on the IO thread.
40   if (!BrowserThread::CurrentlyOn(BrowserThread::IO))
41     return;
42
43   if (entry.source().type == net::NetLog::SOURCE_URL_REQUEST)
44     OnAddURLRequestEntry(entry);
45 }
46
47 void DevToolsNetLogObserver::OnAddURLRequestEntry(
48     const net::NetLog::Entry& entry) {
49   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
50
51   bool is_begin = entry.phase() == net::NetLog::PHASE_BEGIN;
52   bool is_end = entry.phase() == net::NetLog::PHASE_END;
53
54   if (entry.type() == net::NetLog::TYPE_URL_REQUEST_START_JOB) {
55     if (is_begin) {
56       int load_flags;
57       scoped_ptr<base::Value> event_param(entry.ParametersToValue());
58       if (!net::StartEventLoadFlagsFromEventParams(event_param.get(),
59                                                    &load_flags)) {
60         return;
61       }
62
63       if (!(load_flags & net::LOAD_REPORT_RAW_HEADERS))
64         return;
65
66       if (request_to_info_.size() > kMaxNumEntries) {
67         LOG(WARNING) << "The raw headers observer url request count has grown "
68                         "larger than expected, resetting";
69         request_to_info_.clear();
70       }
71
72       request_to_info_[entry.source().id] = new ResourceInfo();
73     }
74     return;
75   } else if (entry.type() == net::NetLog::TYPE_REQUEST_ALIVE) {
76     // Cleanup records based on the TYPE_REQUEST_ALIVE entry.
77     if (is_end)
78       request_to_info_.erase(entry.source().id);
79     return;
80   }
81
82   ResourceInfo* info = GetResourceInfo(entry.source().id);
83   if (!info)
84     return;
85
86   switch (entry.type()) {
87     case net::NetLog::TYPE_HTTP_TRANSACTION_SEND_REQUEST_HEADERS: {
88       scoped_ptr<base::Value> event_params(entry.ParametersToValue());
89       std::string request_line;
90       net::HttpRequestHeaders request_headers;
91
92       if (!net::HttpRequestHeaders::FromNetLogParam(event_params.get(),
93                                                     &request_headers,
94                                                     &request_line)) {
95         NOTREACHED();
96       }
97
98       // We need to clear headers in case the same url_request is reused for
99       // several http requests (e.g. see http://crbug.com/80157).
100       info->request_headers.clear();
101
102       for (net::HttpRequestHeaders::Iterator it(request_headers);
103            it.GetNext();) {
104         info->request_headers.push_back(std::make_pair(it.name(), it.value()));
105       }
106       info->request_headers_text = request_line + request_headers.ToString();
107       break;
108     }
109     case net::NetLog::TYPE_HTTP_TRANSACTION_SPDY_SEND_REQUEST_HEADERS: {
110       scoped_ptr<base::Value> event_params(entry.ParametersToValue());
111       net::SpdyHeaderBlock request_headers;
112
113       if (!net::SpdyHeaderBlockFromNetLogParam(event_params.get(),
114                                                &request_headers)) {
115         NOTREACHED();
116       }
117
118       // We need to clear headers in case the same url_request is reused for
119       // several http requests (e.g. see http://crbug.com/80157).
120       info->request_headers.clear();
121
122       for (net::SpdyHeaderBlock::const_iterator it = request_headers.begin();
123            it != request_headers.end(); ++it) {
124         info->request_headers.push_back(std::make_pair(it->first, it->second));
125       }
126       info->request_headers_text = "";
127       break;
128     }
129     case net::NetLog::TYPE_HTTP_TRANSACTION_READ_RESPONSE_HEADERS: {
130       scoped_ptr<base::Value> event_params(entry.ParametersToValue());
131
132       scoped_refptr<net::HttpResponseHeaders> response_headers;
133
134       if (!net::HttpResponseHeaders::FromNetLogParam(event_params.get(),
135                                                      &response_headers)) {
136         NOTREACHED();
137       }
138
139       info->http_status_code = response_headers->response_code();
140       info->http_status_text = response_headers->GetStatusText();
141       std::string name, value;
142
143       // We need to clear headers in case the same url_request is reused for
144       // several http requests (e.g. see http://crbug.com/80157).
145       info->response_headers.clear();
146
147       for (void* it = NULL;
148            response_headers->EnumerateHeaderLines(&it, &name, &value); ) {
149         info->response_headers.push_back(std::make_pair(name, value));
150       }
151       info->response_headers_text =
152           net::HttpUtil::ConvertHeadersBackToHTTPResponse(
153               response_headers->raw_headers());
154       break;
155     }
156     default:
157       break;
158   }
159 }
160
161 void DevToolsNetLogObserver::Attach() {
162   DCHECK(!instance_);
163   net::NetLog* net_log = GetContentClient()->browser()->GetNetLog();
164   if (net_log) {
165     instance_ = new DevToolsNetLogObserver();
166     net_log->AddThreadSafeObserver(instance_, net::NetLog::LOG_ALL_BUT_BYTES);
167   }
168 }
169
170 void DevToolsNetLogObserver::Detach() {
171   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
172
173   if (instance_) {
174     // Safest not to do this in the destructor to maintain thread safety across
175     // refactorings.
176     instance_->net_log()->RemoveThreadSafeObserver(instance_);
177     delete instance_;
178     instance_ = NULL;
179   }
180 }
181
182 DevToolsNetLogObserver* DevToolsNetLogObserver::GetInstance() {
183   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
184
185   return instance_;
186 }
187
188 // static
189 void DevToolsNetLogObserver::PopulateResponseInfo(
190     net::URLRequest* request,
191     ResourceResponse* response) {
192   if (!(request->load_flags() & net::LOAD_REPORT_RAW_HEADERS))
193     return;
194
195   uint32 source_id = request->net_log().source().id;
196   DevToolsNetLogObserver* dev_tools_net_log_observer =
197       DevToolsNetLogObserver::GetInstance();
198   if (dev_tools_net_log_observer == NULL)
199     return;
200   response->head.devtools_info =
201       dev_tools_net_log_observer->GetResourceInfo(source_id);
202 }
203
204 }  // namespace content