Index: chrome/browser/net/http_pipelining_compatibility_client.cc |
diff --git a/chrome/browser/net/http_pipelining_compatibility_client.cc b/chrome/browser/net/http_pipelining_compatibility_client.cc |
deleted file mode 100644 |
index 3f2ee54f800e3ea434c3657c8359839e97c9d86d..0000000000000000000000000000000000000000 |
--- a/chrome/browser/net/http_pipelining_compatibility_client.cc |
+++ /dev/null |
@@ -1,542 +0,0 @@ |
-// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "chrome/browser/net/http_pipelining_compatibility_client.h" |
- |
-#include "base/metrics/field_trial.h" |
-#include "base/metrics/histogram.h" |
-#include "base/strings/string_number_conversions.h" |
-#include "base/strings/string_split.h" |
-#include "base/strings/stringprintf.h" |
-#include "chrome/browser/io_thread.h" |
-#include "chrome/common/chrome_version_info.h" |
-#include "content/public/browser/browser_thread.h" |
-#include "net/base/load_flags.h" |
-#include "net/base/network_change_notifier.h" |
-#include "net/base/request_priority.h" |
-#include "net/disk_cache/blockfile/histogram_macros.h" |
-#include "net/http/http_network_layer.h" |
-#include "net/http/http_network_session.h" |
-#include "net/http/http_response_headers.h" |
-#include "net/http/http_version.h" |
-#include "net/proxy/proxy_config.h" |
-#include "net/proxy/proxy_service.h" |
-#include "net/url_request/url_request_context.h" |
-#include "net/url_request/url_request_context_getter.h" |
- |
-namespace chrome_browser_net { |
- |
-static const int kCanaryRequestId = 999; |
- |
-namespace { |
- |
-// There is one Request per RequestInfo passed in to Start() above. |
-class Request : public internal::PipelineTestRequest, |
- public net::URLRequest::Delegate { |
- public: |
- Request(int request_id, |
- const std::string& base_url, |
- const RequestInfo& info, |
- internal::PipelineTestRequest::Delegate* delegate, |
- net::URLRequestContext* url_request_context); |
- |
- virtual ~Request() {} |
- |
- virtual void Start() OVERRIDE; |
- |
- protected: |
- // Called when this request has determined its result. Returns the result to |
- // the |client_|. |
- virtual void Finished(internal::PipelineTestRequest::Status result); |
- |
- const std::string& response() const { return response_; } |
- |
- internal::PipelineTestRequest::Delegate* delegate() { return delegate_; } |
- |
- private: |
- // Called when a response can be read. Reads bytes into |response_| until it |
- // consumes the entire response or it encounters an error. |
- void DoRead(); |
- |
- // Called when all bytes have been received. Compares the |response_| to |
- // |info_|'s expected response. |
- virtual void DoReadFinished(); |
- |
- // net::URLRequest::Delegate interface |
- virtual void OnReceivedRedirect(net::URLRequest* request, |
- const GURL& new_url, |
- bool* defer_redirect) OVERRIDE; |
- virtual void OnSSLCertificateError(net::URLRequest* request, |
- const net::SSLInfo& ssl_info, |
- bool fatal) OVERRIDE; |
- virtual void OnResponseStarted(net::URLRequest* request) OVERRIDE; |
- virtual void OnReadCompleted(net::URLRequest* request, |
- int bytes_read) OVERRIDE; |
- |
- internal::PipelineTestRequest::Delegate* delegate_; |
- const int request_id_; |
- scoped_ptr<net::URLRequest> url_request_; |
- const RequestInfo info_; |
- scoped_refptr<net::IOBuffer> read_buffer_; |
- std::string response_; |
- int response_code_; |
-}; |
- |
-Request::Request(int request_id, |
- const std::string& base_url, |
- const RequestInfo& info, |
- internal::PipelineTestRequest::Delegate* delegate, |
- net::URLRequestContext* url_request_context) |
- : delegate_(delegate), |
- request_id_(request_id), |
- url_request_(url_request_context->CreateRequest(GURL(base_url + |
- info.filename), |
- net::DEFAULT_PRIORITY, |
- this, |
- NULL)), |
- info_(info), |
- response_code_(0) { |
- url_request_->SetLoadFlags(net::LOAD_BYPASS_CACHE | |
- net::LOAD_DISABLE_CACHE | |
- net::LOAD_DO_NOT_SAVE_COOKIES | |
- net::LOAD_DO_NOT_SEND_COOKIES | |
- net::LOAD_DO_NOT_PROMPT_FOR_LOGIN | |
- net::LOAD_DO_NOT_SEND_AUTH_DATA); |
-} |
- |
-void Request::Start() { |
- url_request_->Start(); |
-} |
- |
-void Request::OnReceivedRedirect( |
- net::URLRequest* request, |
- const GURL& new_url, |
- bool* defer_redirect) { |
- *defer_redirect = true; |
- request->Cancel(); |
- Finished(STATUS_REDIRECTED); |
-} |
- |
-void Request::OnSSLCertificateError( |
- net::URLRequest* request, |
- const net::SSLInfo& ssl_info, |
- bool fatal) { |
- Finished(STATUS_CERT_ERROR); |
-} |
- |
-void Request::OnResponseStarted(net::URLRequest* request) { |
- response_code_ = request->GetResponseCode(); |
- if (response_code_ != 200) { |
- Finished(STATUS_BAD_RESPONSE_CODE); |
- return; |
- } |
- const net::HttpVersion required_version(1, 1); |
- if (request->response_info().headers->GetParsedHttpVersion() < |
- required_version) { |
- Finished(STATUS_BAD_HTTP_VERSION); |
- return; |
- } |
- read_buffer_ = new net::IOBuffer(info_.expected_response.length()); |
- DoRead(); |
-} |
- |
-void Request::OnReadCompleted(net::URLRequest* request, int bytes_read) { |
- if (bytes_read == 0) { |
- DoReadFinished(); |
- } else if (bytes_read < 0) { |
- Finished(STATUS_NETWORK_ERROR); |
- } else { |
- response_.append(read_buffer_->data(), bytes_read); |
- if (response_.length() <= info_.expected_response.length()) { |
- DoRead(); |
- } else if (response_.find(info_.expected_response) == 0) { |
- Finished(STATUS_TOO_LARGE); |
- } else { |
- Finished(STATUS_CONTENT_MISMATCH); |
- } |
- } |
-} |
- |
-void Request::DoRead() { |
- int bytes_read = 0; |
- if (url_request_->Read(read_buffer_.get(), info_.expected_response.length(), |
- &bytes_read)) { |
- OnReadCompleted(url_request_.get(), bytes_read); |
- } |
-} |
- |
-void Request::DoReadFinished() { |
- if (response_.length() != info_.expected_response.length()) { |
- if (info_.expected_response.find(response_) == 0) { |
- Finished(STATUS_TOO_SMALL); |
- } else { |
- Finished(STATUS_CONTENT_MISMATCH); |
- } |
- } else if (response_ == info_.expected_response) { |
- Finished(STATUS_SUCCESS); |
- } else { |
- Finished(STATUS_CONTENT_MISMATCH); |
- } |
-} |
- |
-void Request::Finished(internal::PipelineTestRequest::Status result) { |
- const net::URLRequestStatus status = url_request_->status(); |
- url_request_.reset(); |
- if (response_code_ > 0) { |
- delegate()->ReportResponseCode(request_id_, response_code_); |
- } |
- if (status.status() == net::URLRequestStatus::FAILED) { |
- // Network errors trump all other status codes, because network errors can |
- // be detected by the network stack even with real content. If we determine |
- // that all pipelining errors can be detected by the network stack, then we |
- // don't need to worry about broken proxies. |
- delegate()->ReportNetworkError(request_id_, status.error()); |
- delegate()->OnRequestFinished(request_id_, STATUS_NETWORK_ERROR); |
- } else { |
- delegate()->OnRequestFinished(request_id_, result); |
- } |
- // WARNING: We may be deleted at this point. |
-} |
- |
-// A special non-pipelined request sent before pipelining begins to test basic |
-// HTTP connectivity. |
-class CanaryRequest : public Request { |
- public: |
- CanaryRequest(int request_id, |
- const std::string& base_url, |
- const RequestInfo& info, |
- internal::PipelineTestRequest::Delegate* delegate, |
- net::URLRequestContext* url_request_context) |
- : Request(request_id, base_url, info, delegate, url_request_context) { |
- } |
- |
- virtual ~CanaryRequest() {} |
- |
- private: |
- virtual void Finished( |
- internal::PipelineTestRequest::Status result) OVERRIDE { |
- delegate()->OnCanaryFinished(result); |
- } |
-}; |
- |
-// A special request that parses a /stats.txt response from the test server. |
-class StatsRequest : public Request { |
- public: |
- // Note that |info.expected_response| is only used to determine the correct |
- // length of the response. The exact string content isn't used. |
- StatsRequest(int request_id, |
- const std::string& base_url, |
- const RequestInfo& info, |
- internal::PipelineTestRequest::Delegate* delegate, |
- net::URLRequestContext* url_request_context) |
- : Request(request_id, base_url, info, delegate, url_request_context) { |
- } |
- |
- virtual ~StatsRequest() {} |
- |
- private: |
- virtual void DoReadFinished() OVERRIDE { |
- internal::PipelineTestRequest::Status status = |
- internal::ProcessStatsResponse(response()); |
- Finished(status); |
- } |
-}; |
- |
-class RequestFactory : public internal::PipelineTestRequest::Factory { |
- public: |
- virtual internal::PipelineTestRequest* NewRequest( |
- int request_id, |
- const std::string& base_url, |
- const RequestInfo& info, |
- internal::PipelineTestRequest::Delegate* delegate, |
- net::URLRequestContext* url_request_context, |
- internal::PipelineTestRequest::Type request_type) OVERRIDE { |
- switch (request_type) { |
- case internal::PipelineTestRequest::TYPE_PIPELINED: |
- return new Request(request_id, base_url, info, delegate, |
- url_request_context); |
- |
- case internal::PipelineTestRequest::TYPE_CANARY: |
- return new CanaryRequest(request_id, base_url, info, delegate, |
- url_request_context); |
- |
- case internal::PipelineTestRequest::TYPE_STATS: |
- return new StatsRequest(request_id, base_url, info, delegate, |
- url_request_context); |
- |
- default: |
- NOTREACHED(); |
- return NULL; |
- } |
- } |
-}; |
- |
-} // anonymous namespace |
- |
-HttpPipeliningCompatibilityClient::HttpPipeliningCompatibilityClient( |
- internal::PipelineTestRequest::Factory* factory) |
- : factory_(factory), |
- num_finished_(0), |
- num_succeeded_(0) { |
- if (!factory_.get()) { |
- factory_.reset(new RequestFactory); |
- } |
-} |
- |
-HttpPipeliningCompatibilityClient::~HttpPipeliningCompatibilityClient() { |
-} |
- |
-void HttpPipeliningCompatibilityClient::Start( |
- const std::string& base_url, |
- std::vector<RequestInfo>& requests, |
- Options options, |
- const net::CompletionCallback& callback, |
- net::URLRequestContext* url_request_context) { |
- net::HttpNetworkSession* old_session = |
- url_request_context->http_transaction_factory()->GetSession(); |
- net::HttpNetworkSession::Params params = old_session->params(); |
- params.force_http_pipelining = true; |
- scoped_refptr<net::HttpNetworkSession> session = |
- new net::HttpNetworkSession(params); |
- http_transaction_factory_.reset( |
- net::HttpNetworkLayer::CreateFactory(session.get())); |
- |
- url_request_context_.reset(new net::URLRequestContext); |
- url_request_context_->CopyFrom(url_request_context); |
- url_request_context_->set_http_transaction_factory( |
- http_transaction_factory_.get()); |
- |
- finished_callback_ = callback; |
- for (size_t i = 0; i < requests.size(); ++i) { |
- requests_.push_back(factory_->NewRequest( |
- i, base_url, requests[i], this, url_request_context_.get(), |
- internal::PipelineTestRequest::TYPE_PIPELINED)); |
- } |
- if (options == PIPE_TEST_COLLECT_SERVER_STATS || |
- options == PIPE_TEST_CANARY_AND_STATS) { |
- RequestInfo info; |
- info.filename = "stats.txt"; |
- // This is just to determine the expected length of the response. |
- // StatsRequest doesn't expect this exact value, but it does expect this |
- // exact length. |
- info.expected_response = |
- "were_all_requests_http_1_1:1,max_pipeline_depth:5"; |
- requests_.push_back(factory_->NewRequest( |
- requests.size(), base_url, info, this, url_request_context_.get(), |
- internal::PipelineTestRequest::TYPE_STATS)); |
- } |
- if (options == PIPE_TEST_RUN_CANARY_REQUEST || |
- options == PIPE_TEST_CANARY_AND_STATS) { |
- RequestInfo info; |
- info.filename = "index.html"; |
- info.expected_response = |
- "\nThis is a test server operated by Google. It's used by Google " |
- "Chrome to test\nproxies for compatibility with HTTP pipelining. More " |
- "information can be found\nhere:\n\nhttp://dev.chromium.org/developers/" |
- "design-documents/network-stack/http-pipelining\n\nSource code can be " |
- "found here:\n\nhttp://code.google.com/p/http-pipelining-test/\n"; |
- canary_request_.reset(factory_->NewRequest( |
- kCanaryRequestId, base_url, info, this, url_request_context, |
- internal::PipelineTestRequest::TYPE_CANARY)); |
- canary_request_->Start(); |
- } else { |
- StartTestRequests(); |
- } |
-} |
- |
-void HttpPipeliningCompatibilityClient::StartTestRequests() { |
- for (size_t i = 0; i < requests_.size(); ++i) { |
- requests_[i]->Start(); |
- } |
-} |
- |
-void HttpPipeliningCompatibilityClient::OnCanaryFinished( |
- internal::PipelineTestRequest::Status status) { |
- canary_request_.reset(); |
- bool success = (status == internal::PipelineTestRequest::STATUS_SUCCESS); |
- UMA_HISTOGRAM_BOOLEAN("NetConnectivity.Pipeline.CanarySuccess", success); |
- if (success) { |
- StartTestRequests(); |
- } else { |
- finished_callback_.Run(0); |
- } |
-} |
- |
-void HttpPipeliningCompatibilityClient::OnRequestFinished( |
- int request_id, internal::PipelineTestRequest::Status status) { |
- // The CACHE_HISTOGRAM_* macros are used, because they allow dynamic metric |
- // names. |
- // TODO(gavinp): Clean up this dependency by moving the needed functionality |
- // into base/. |
- CACHE_HISTOGRAM_ENUMERATION(GetMetricName(request_id, "Status"), |
- status, |
- internal::PipelineTestRequest::STATUS_MAX); |
- |
- ++num_finished_; |
- if (status == internal::PipelineTestRequest::STATUS_SUCCESS) { |
- ++num_succeeded_; |
- } |
- if (num_finished_ == requests_.size()) { |
- UMA_HISTOGRAM_BOOLEAN("NetConnectivity.Pipeline.Success", |
- num_succeeded_ == requests_.size()); |
- finished_callback_.Run(0); |
- } |
-} |
- |
-void HttpPipeliningCompatibilityClient::ReportNetworkError(int request_id, |
- int error_code) { |
- CACHE_HISTOGRAM_ENUMERATION(GetMetricName(request_id, "NetworkError"), |
- -error_code, 900); |
-} |
- |
-void HttpPipeliningCompatibilityClient::ReportResponseCode(int request_id, |
- int response_code) { |
- CACHE_HISTOGRAM_ENUMERATION(GetMetricName(request_id, "ResponseCode"), |
- response_code, 600); |
-} |
- |
-std::string HttpPipeliningCompatibilityClient::GetMetricName( |
- int request_id, const char* description) { |
- return base::StringPrintf("NetConnectivity.Pipeline.%d.%s", |
- request_id, description); |
-} |
- |
-namespace internal { |
- |
-internal::PipelineTestRequest::Status ProcessStatsResponse( |
- const std::string& response) { |
- bool were_all_requests_http_1_1 = false; |
- int max_pipeline_depth = 0; |
- |
- std::vector<std::pair<std::string, std::string> > kv_pairs; |
- base::SplitStringIntoKeyValuePairs(response, ':', ',', &kv_pairs); |
- |
- if (kv_pairs.size() != 2) { |
- return internal::PipelineTestRequest::STATUS_CORRUPT_STATS; |
- } |
- |
- for (size_t i = 0; i < kv_pairs.size(); ++i) { |
- const std::string& key = kv_pairs[i].first; |
- int value; |
- if (!base::StringToInt(kv_pairs[i].second, &value)) { |
- return internal::PipelineTestRequest::STATUS_CORRUPT_STATS; |
- } |
- |
- if (key == "were_all_requests_http_1_1") { |
- were_all_requests_http_1_1 = (value == 1); |
- } else if (key == "max_pipeline_depth") { |
- max_pipeline_depth = value; |
- } else { |
- return internal::PipelineTestRequest::STATUS_CORRUPT_STATS; |
- } |
- } |
- |
- UMA_HISTOGRAM_BOOLEAN("NetConnectivity.Pipeline.AllHTTP11", |
- were_all_requests_http_1_1); |
- UMA_HISTOGRAM_ENUMERATION("NetConnectivity.Pipeline.Depth", |
- max_pipeline_depth, 6); |
- |
- return internal::PipelineTestRequest::STATUS_SUCCESS; |
-} |
- |
-} // namespace internal |
- |
-namespace { |
- |
-void DeleteClient(IOThread* io_thread, int /* rv */) { |
- DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); |
- io_thread->globals()->http_pipelining_compatibility_client.reset(); |
-} |
- |
-void CollectPipeliningCapabilityStatsOnIOThread( |
- const std::string& pipeline_test_server, |
- IOThread* io_thread) { |
- DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); |
- |
- net::URLRequestContext* url_request_context = |
- io_thread->globals()->system_request_context.get(); |
- if (!url_request_context->proxy_service()->config().proxy_rules().empty()) { |
- // Pipelining with explicitly configured proxies is disabled for now. |
- return; |
- } |
- |
- const base::FieldTrial::Probability kDivisor = 100; |
- base::FieldTrial::Probability probability_to_run_test = 0; |
- |
- const char* kTrialName = "HttpPipeliningCompatibility"; |
- base::FieldTrial* trial = base::FieldTrialList::Find(kTrialName); |
- if (trial) { |
- return; |
- } |
- // After May 4, 2012, the trial will disable itself. |
- trial = base::FieldTrialList::FactoryGetFieldTrial( |
- kTrialName, kDivisor, "disable_test", 2012, 5, 4, |
- base::FieldTrial::SESSION_RANDOMIZED, NULL); |
- |
- chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel(); |
- if (channel == chrome::VersionInfo::CHANNEL_CANARY) { |
- probability_to_run_test = 100; |
- } else if (channel == chrome::VersionInfo::CHANNEL_DEV) { |
- probability_to_run_test = 100; |
- } |
- |
- int collect_stats_group = trial->AppendGroup("enable_test", |
- probability_to_run_test); |
- if (trial->group() != collect_stats_group) { |
- return; |
- } |
- |
- std::vector<RequestInfo> requests; |
- |
- RequestInfo info0; |
- info0.filename = "alphabet.txt"; |
- info0.expected_response = "abcdefghijklmnopqrstuvwxyz"; |
- requests.push_back(info0); |
- |
- RequestInfo info1; |
- info1.filename = "cached.txt"; |
- info1.expected_response = "azbycxdwevfugthsirjqkplomn"; |
- requests.push_back(info1); |
- |
- RequestInfo info2; |
- info2.filename = "reverse.txt"; |
- info2.expected_response = "zyxwvutsrqponmlkjihgfedcba"; |
- requests.push_back(info2); |
- |
- RequestInfo info3; |
- info3.filename = "chunked.txt"; |
- info3.expected_response = "chunkedencodingisfun"; |
- requests.push_back(info3); |
- |
- RequestInfo info4; |
- info4.filename = "cached.txt"; |
- info4.expected_response = "azbycxdwevfugthsirjqkplomn"; |
- requests.push_back(info4); |
- |
- HttpPipeliningCompatibilityClient* client = |
- new HttpPipeliningCompatibilityClient(NULL); |
- client->Start(pipeline_test_server, requests, |
- HttpPipeliningCompatibilityClient::PIPE_TEST_CANARY_AND_STATS, |
- base::Bind(&DeleteClient, io_thread), |
- url_request_context); |
- io_thread->globals()->http_pipelining_compatibility_client.reset(client); |
-} |
- |
-} // anonymous namespace |
- |
-void CollectPipeliningCapabilityStatsOnUIThread( |
- const std::string& pipeline_test_server, IOThread* io_thread) { |
- DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
- if (pipeline_test_server.empty()) |
- return; |
- |
- content::BrowserThread::PostTask( |
- content::BrowserThread::IO, |
- FROM_HERE, |
- base::Bind(&CollectPipeliningCapabilityStatsOnIOThread, |
- pipeline_test_server, |
- io_thread)); |
-} |
- |
-} // namespace chrome_browser_net |