Home | History | Annotate | Download | only in devtools
      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