1// Copyright 2014 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/devtools/devtools_network_transaction.h" 6 7#include "chrome/browser/devtools/devtools_network_controller.h" 8#include "chrome/browser/devtools/devtools_network_interceptor.h" 9#include "net/base/net_errors.h" 10#include "net/base/upload_progress.h" 11#include "net/http/http_network_transaction.h" 12#include "net/http/http_request_info.h" 13 14namespace { 15 16const char kDevToolsRequestInitiator[] = "X-DevTools-Request-Initiator"; 17const char kDevToolsEmulateNetworkConditionsClientId[] = 18 "X-DevTools-Emulate-Network-Conditions-Client-Id"; 19 20} // namespace 21 22DevToolsNetworkTransaction::DevToolsNetworkTransaction( 23 DevToolsNetworkController* controller, 24 scoped_ptr<net::HttpTransaction> network_transaction) 25 : controller_(controller), 26 network_transaction_(network_transaction.Pass()), 27 request_(NULL), 28 failed_(false), 29 throttled_byte_count_(0), 30 callback_type_(NONE), 31 proxy_callback_(base::Bind(&DevToolsNetworkTransaction::OnCallback, 32 base::Unretained(this))) { 33 DCHECK(controller); 34} 35 36DevToolsNetworkTransaction::~DevToolsNetworkTransaction() { 37 if (interceptor_) 38 interceptor_->RemoveTransaction(this); 39} 40 41void DevToolsNetworkTransaction::Throttle(int result) { 42 throttled_result_ = result; 43 44 if (callback_type_ == START) 45 throttled_byte_count_ += network_transaction_->GetTotalReceivedBytes(); 46 if (result > 0) 47 throttled_byte_count_ += result; 48 49 if (interceptor_) 50 interceptor_->ThrottleTransaction(this, callback_type_ == START); 51} 52 53void DevToolsNetworkTransaction::OnCallback(int rv) { 54 if (failed_) 55 return; 56 DCHECK(!callback_.is_null()); 57 if (callback_type_ == START || callback_type_ == READ) { 58 if (interceptor_ && interceptor_->ShouldThrottle(this)) { 59 Throttle(rv); 60 return; 61 } 62 } 63 net::CompletionCallback callback = callback_; 64 callback_.Reset(); 65 callback_type_ = NONE; 66 callback.Run(rv); 67} 68 69int DevToolsNetworkTransaction::SetupCallback( 70 net::CompletionCallback callback, 71 int result, 72 CallbackType callback_type) { 73 DCHECK(callback_type_ == NONE); 74 75 if (result == net::ERR_IO_PENDING) { 76 callback_type_ = callback_type; 77 callback_ = callback; 78 return result; 79 } 80 81 if (!interceptor_ || !interceptor_->ShouldThrottle(this)) 82 return result; 83 84 // Only START and READ operation throttling is supported. 85 if (callback_type != START && callback_type != READ) 86 return result; 87 88 // In case of error |throttled_byte_count_| is unknown. 89 if (result < 0) 90 return result; 91 92 // URLRequestJob relies on synchronous end-of-stream notification. 93 if (callback_type == READ && result == 0) 94 return result; 95 96 callback_type_ = callback_type; 97 callback_ = callback; 98 Throttle(result); 99 return net::ERR_IO_PENDING; 100} 101 102void DevToolsNetworkTransaction::Fail() { 103 DCHECK(request_); 104 DCHECK(!failed_); 105 failed_ = true; 106 network_transaction_->SetBeforeNetworkStartCallback( 107 BeforeNetworkStartCallback()); 108 if (callback_.is_null()) 109 return; 110 net::CompletionCallback callback = callback_; 111 callback_.Reset(); 112 callback_type_ = NONE; 113 callback.Run(net::ERR_INTERNET_DISCONNECTED); 114} 115 116int DevToolsNetworkTransaction::Start( 117 const net::HttpRequestInfo* request, 118 const net::CompletionCallback& callback, 119 const net::BoundNetLog& net_log) { 120 DCHECK(request); 121 request_ = request; 122 interceptor_ = controller_->GetInterceptor(this); 123 interceptor_->AddTransaction(this); 124 125 if (interceptor_->ShouldFail(this)) { 126 failed_ = true; 127 network_transaction_->SetBeforeNetworkStartCallback( 128 BeforeNetworkStartCallback()); 129 return net::ERR_INTERNET_DISCONNECTED; 130 } 131 int rv = network_transaction_->Start(request_, proxy_callback_, net_log); 132 return SetupCallback(callback, rv, START); 133} 134 135void DevToolsNetworkTransaction::ProcessRequest() { 136 DCHECK(request_); 137 bool has_devtools_client_id = request_->extra_headers.HasHeader( 138 kDevToolsEmulateNetworkConditionsClientId); 139 bool has_devtools_request_initiator = request_->extra_headers.HasHeader( 140 kDevToolsRequestInitiator); 141 if (!has_devtools_client_id && !has_devtools_request_initiator) 142 return; 143 144 custom_request_.reset(new net::HttpRequestInfo(*request_)); 145 146 if (has_devtools_client_id) { 147 custom_request_->extra_headers.GetHeader( 148 kDevToolsEmulateNetworkConditionsClientId, &client_id_); 149 custom_request_->extra_headers.RemoveHeader( 150 kDevToolsEmulateNetworkConditionsClientId); 151 } 152 153 if (has_devtools_request_initiator) { 154 custom_request_->extra_headers.GetHeader( 155 kDevToolsRequestInitiator, &request_initiator_); 156 custom_request_->extra_headers.RemoveHeader(kDevToolsRequestInitiator); 157 } 158 159 request_ = custom_request_.get(); 160} 161 162int DevToolsNetworkTransaction::RestartIgnoringLastError( 163 const net::CompletionCallback& callback) { 164 if (failed_) 165 return net::ERR_INTERNET_DISCONNECTED; 166 int rv = network_transaction_->RestartIgnoringLastError(proxy_callback_); 167 return SetupCallback(callback, rv, RESTART_IGNORING_LAST_ERROR); 168} 169 170int DevToolsNetworkTransaction::RestartWithCertificate( 171 net::X509Certificate* client_cert, 172 const net::CompletionCallback& callback) { 173 if (failed_) 174 return net::ERR_INTERNET_DISCONNECTED; 175 int rv = network_transaction_->RestartWithCertificate( 176 client_cert, proxy_callback_); 177 return SetupCallback(callback, rv, RESTART_WITH_CERTIFICATE); 178} 179 180int DevToolsNetworkTransaction::RestartWithAuth( 181 const net::AuthCredentials& credentials, 182 const net::CompletionCallback& callback) { 183 if (failed_) 184 return net::ERR_INTERNET_DISCONNECTED; 185 int rv = network_transaction_->RestartWithAuth(credentials, proxy_callback_); 186 return SetupCallback(callback, rv, RESTART_WITH_AUTH); 187} 188 189bool DevToolsNetworkTransaction::IsReadyToRestartForAuth() { 190 return network_transaction_->IsReadyToRestartForAuth(); 191} 192 193int DevToolsNetworkTransaction::Read( 194 net::IOBuffer* buf, 195 int buf_len, 196 const net::CompletionCallback& callback) { 197 if (failed_) 198 return net::ERR_INTERNET_DISCONNECTED; 199 int rv = network_transaction_->Read(buf, buf_len, proxy_callback_); 200 return SetupCallback(callback, rv, READ); 201} 202 203void DevToolsNetworkTransaction::StopCaching() { 204 network_transaction_->StopCaching(); 205} 206 207bool DevToolsNetworkTransaction::GetFullRequestHeaders( 208 net::HttpRequestHeaders* headers) const { 209 return network_transaction_->GetFullRequestHeaders(headers); 210} 211 212int64 DevToolsNetworkTransaction::GetTotalReceivedBytes() const { 213 return network_transaction_->GetTotalReceivedBytes(); 214} 215 216void DevToolsNetworkTransaction::DoneReading() { 217 network_transaction_->DoneReading(); 218} 219 220const net::HttpResponseInfo* 221DevToolsNetworkTransaction::GetResponseInfo() const { 222 return network_transaction_->GetResponseInfo(); 223} 224 225net::LoadState DevToolsNetworkTransaction::GetLoadState() const { 226 return network_transaction_->GetLoadState(); 227} 228 229net::UploadProgress DevToolsNetworkTransaction::GetUploadProgress() const { 230 return network_transaction_->GetUploadProgress(); 231} 232 233void DevToolsNetworkTransaction::SetQuicServerInfo( 234 net::QuicServerInfo* quic_server_info) { 235 network_transaction_->SetQuicServerInfo(quic_server_info); 236} 237 238bool DevToolsNetworkTransaction::GetLoadTimingInfo( 239 net::LoadTimingInfo* load_timing_info) const { 240 return network_transaction_->GetLoadTimingInfo(load_timing_info); 241} 242 243void DevToolsNetworkTransaction::SetPriority(net::RequestPriority priority) { 244 network_transaction_->SetPriority(priority); 245} 246 247void DevToolsNetworkTransaction::SetWebSocketHandshakeStreamCreateHelper( 248 net::WebSocketHandshakeStreamBase::CreateHelper* create_helper) { 249 network_transaction_->SetWebSocketHandshakeStreamCreateHelper(create_helper); 250} 251 252void DevToolsNetworkTransaction::SetBeforeNetworkStartCallback( 253 const BeforeNetworkStartCallback& callback) { 254 network_transaction_->SetBeforeNetworkStartCallback(callback); 255} 256 257void DevToolsNetworkTransaction::SetBeforeProxyHeadersSentCallback( 258 const BeforeProxyHeadersSentCallback& callback) { 259 network_transaction_->SetBeforeProxyHeadersSentCallback(callback); 260} 261 262int DevToolsNetworkTransaction::ResumeNetworkStart() { 263 if (failed_) 264 return net::ERR_INTERNET_DISCONNECTED; 265 return network_transaction_->ResumeNetworkStart(); 266} 267 268void DevToolsNetworkTransaction::FireThrottledCallback() { 269 DCHECK(!callback_.is_null()); 270 DCHECK(callback_type_ == READ || callback_type_ == START); 271 net::CompletionCallback callback = callback_; 272 callback_.Reset(); 273 callback_type_ = NONE; 274 callback.Run(throttled_result_); 275} 276