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 14 namespace { 15 16 const char kDevToolsRequestInitiator[] = "X-DevTools-Request-Initiator"; 17 const char kDevToolsEmulateNetworkConditionsClientId[] = 18 "X-DevTools-Emulate-Network-Conditions-Client-Id"; 19 20 } // namespace 21 22 DevToolsNetworkTransaction::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 36 DevToolsNetworkTransaction::~DevToolsNetworkTransaction() { 37 if (interceptor_) 38 interceptor_->RemoveTransaction(this); 39 } 40 41 void 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 53 void 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 69 int 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 102 void 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 116 int 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 135 void 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 162 int 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 170 int 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 180 int 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 189 bool DevToolsNetworkTransaction::IsReadyToRestartForAuth() { 190 return network_transaction_->IsReadyToRestartForAuth(); 191 } 192 193 int 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 203 void DevToolsNetworkTransaction::StopCaching() { 204 network_transaction_->StopCaching(); 205 } 206 207 bool DevToolsNetworkTransaction::GetFullRequestHeaders( 208 net::HttpRequestHeaders* headers) const { 209 return network_transaction_->GetFullRequestHeaders(headers); 210 } 211 212 int64 DevToolsNetworkTransaction::GetTotalReceivedBytes() const { 213 return network_transaction_->GetTotalReceivedBytes(); 214 } 215 216 void DevToolsNetworkTransaction::DoneReading() { 217 network_transaction_->DoneReading(); 218 } 219 220 const net::HttpResponseInfo* 221 DevToolsNetworkTransaction::GetResponseInfo() const { 222 return network_transaction_->GetResponseInfo(); 223 } 224 225 net::LoadState DevToolsNetworkTransaction::GetLoadState() const { 226 return network_transaction_->GetLoadState(); 227 } 228 229 net::UploadProgress DevToolsNetworkTransaction::GetUploadProgress() const { 230 return network_transaction_->GetUploadProgress(); 231 } 232 233 void DevToolsNetworkTransaction::SetQuicServerInfo( 234 net::QuicServerInfo* quic_server_info) { 235 network_transaction_->SetQuicServerInfo(quic_server_info); 236 } 237 238 bool DevToolsNetworkTransaction::GetLoadTimingInfo( 239 net::LoadTimingInfo* load_timing_info) const { 240 return network_transaction_->GetLoadTimingInfo(load_timing_info); 241 } 242 243 void DevToolsNetworkTransaction::SetPriority(net::RequestPriority priority) { 244 network_transaction_->SetPriority(priority); 245 } 246 247 void DevToolsNetworkTransaction::SetWebSocketHandshakeStreamCreateHelper( 248 net::WebSocketHandshakeStreamBase::CreateHelper* create_helper) { 249 network_transaction_->SetWebSocketHandshakeStreamCreateHelper(create_helper); 250 } 251 252 void DevToolsNetworkTransaction::SetBeforeNetworkStartCallback( 253 const BeforeNetworkStartCallback& callback) { 254 network_transaction_->SetBeforeNetworkStartCallback(callback); 255 } 256 257 int DevToolsNetworkTransaction::ResumeNetworkStart() { 258 if (failed_) 259 return net::ERR_INTERNET_DISCONNECTED; 260 return network_transaction_->ResumeNetworkStart(); 261 } 262 263 void DevToolsNetworkTransaction::FireThrottledCallback() { 264 DCHECK(!callback_.is_null()); 265 DCHECK(callback_type_ == READ || callback_type_ == START); 266 net::CompletionCallback callback = callback_; 267 callback_.Reset(); 268 callback_type_ = NONE; 269 callback.Run(throttled_result_); 270 } 271