OLD | NEW |
| (Empty) |
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 "chrome/browser/net/http_pipelining_compatibility_client.h" | |
6 | |
7 #include "base/metrics/histogram.h" | |
8 #include "base/stringprintf.h" | |
9 #include "net/base/load_flags.h" | |
10 #include "net/disk_cache/histogram_macros.h" | |
11 #include "net/http/http_response_headers.h" | |
12 #include "net/http/http_version.h" | |
13 | |
14 namespace chrome_browser_net { | |
15 | |
16 HttpPipeliningCompatibilityClient::HttpPipeliningCompatibilityClient() | |
17 : num_finished_(0) { | |
18 } | |
19 | |
20 HttpPipeliningCompatibilityClient::~HttpPipeliningCompatibilityClient() { | |
21 } | |
22 | |
23 void HttpPipeliningCompatibilityClient::Start( | |
24 const std::string& base_url, | |
25 std::vector<RequestInfo>& requests, | |
26 const net::CompletionCallback& callback, | |
27 net::URLRequestContext* url_request_context) { | |
28 finished_callback_ = callback; | |
29 for (size_t i = 0; i < requests.size(); ++i) { | |
30 requests_.push_back(new Request(i, base_url, requests[i], this, | |
31 url_request_context)); | |
32 } | |
33 } | |
34 | |
35 void HttpPipeliningCompatibilityClient::OnRequestFinished(int request_id, | |
36 Status status) { | |
37 // The CACHE_HISTOGRAM_* macros are used, because they allow dynamic metric | |
38 // names. | |
39 CACHE_HISTOGRAM_ENUMERATION(GetMetricName(request_id, "Status"), | |
40 status, STATUS_MAX); | |
41 ++num_finished_; | |
42 if (num_finished_ == requests_.size()) { | |
43 finished_callback_.Run(0); | |
44 } | |
45 } | |
46 | |
47 void HttpPipeliningCompatibilityClient::ReportNetworkError(int request_id, | |
48 int error_code) { | |
49 CACHE_HISTOGRAM_ENUMERATION(GetMetricName(request_id, "NetworkError"), | |
50 -error_code, 900); | |
51 } | |
52 | |
53 void HttpPipeliningCompatibilityClient::ReportResponseCode(int request_id, | |
54 int response_code) { | |
55 CACHE_HISTOGRAM_ENUMERATION(GetMetricName(request_id, "ResponseCode"), | |
56 response_code, 600); | |
57 } | |
58 | |
59 std::string HttpPipeliningCompatibilityClient::GetMetricName( | |
60 int request_id, const char* description) { | |
61 return base::StringPrintf("NetConnectivity.Pipeline.%d.%s", | |
62 request_id, description); | |
63 } | |
64 | |
65 HttpPipeliningCompatibilityClient::Request::Request( | |
66 int request_id, | |
67 const std::string& base_url, | |
68 const RequestInfo& info, | |
69 HttpPipeliningCompatibilityClient* client, | |
70 net::URLRequestContext* url_request_context) | |
71 : request_id_(request_id), | |
72 request_(GURL(base_url + info.filename), this), | |
73 info_(info), | |
74 client_(client), | |
75 finished_(false) { | |
76 request_.set_context(url_request_context); | |
77 // TODO(simonjam): Force pipelining. | |
78 request_.set_load_flags(net::LOAD_BYPASS_CACHE | | |
79 net::LOAD_DISABLE_CACHE | | |
80 net::LOAD_DO_NOT_SAVE_COOKIES | | |
81 net::LOAD_DO_NOT_SEND_COOKIES | | |
82 net::LOAD_DO_NOT_PROMPT_FOR_LOGIN | | |
83 net::LOAD_DO_NOT_SEND_AUTH_DATA); | |
84 request_.Start(); | |
85 } | |
86 | |
87 HttpPipeliningCompatibilityClient::Request::~Request() { | |
88 } | |
89 | |
90 void HttpPipeliningCompatibilityClient::Request::OnReceivedRedirect( | |
91 net::URLRequest* request, | |
92 const GURL& new_url, | |
93 bool* defer_redirect) { | |
94 *defer_redirect = true; | |
95 request->Cancel(); | |
96 Finished(REDIRECTED); | |
97 } | |
98 | |
99 void HttpPipeliningCompatibilityClient::Request::OnSSLCertificateError( | |
100 net::URLRequest* request, | |
101 const net::SSLInfo& ssl_info, | |
102 bool fatal) { | |
103 Finished(CERT_ERROR); | |
104 } | |
105 | |
106 void HttpPipeliningCompatibilityClient::Request::OnResponseStarted( | |
107 net::URLRequest* request) { | |
108 if (finished_) { | |
109 return; | |
110 } | |
111 int response_code = request->GetResponseCode(); | |
112 if (response_code > 0) { | |
113 client_->ReportResponseCode(request_id_, response_code); | |
114 } | |
115 if (response_code == 200) { | |
116 const net::HttpVersion required_version(1, 1); | |
117 if (request->response_info().headers->GetParsedHttpVersion() < | |
118 required_version) { | |
119 Finished(BAD_HTTP_VERSION); | |
120 } else { | |
121 read_buffer_ = new net::IOBuffer(info_.expected_response.length()); | |
122 DoRead(); | |
123 } | |
124 } else { | |
125 Finished(BAD_RESPONSE_CODE); | |
126 } | |
127 } | |
128 | |
129 void HttpPipeliningCompatibilityClient::Request::OnReadCompleted( | |
130 net::URLRequest* request, | |
131 int bytes_read) { | |
132 if (bytes_read == 0) { | |
133 DoReadFinished(); | |
134 } else if (bytes_read < 0) { | |
135 Finished(NETWORK_ERROR); | |
136 } else { | |
137 response_.append(read_buffer_->data(), bytes_read); | |
138 if (response_.length() <= info_.expected_response.length()) { | |
139 DoRead(); | |
140 } else if (response_.find(info_.expected_response) == 0) { | |
141 Finished(TOO_LARGE); | |
142 } else { | |
143 Finished(CONTENT_MISMATCH); | |
144 } | |
145 } | |
146 } | |
147 | |
148 void HttpPipeliningCompatibilityClient::Request::DoRead() { | |
149 int bytes_read = 0; | |
150 if (request_.Read(read_buffer_.get(), info_.expected_response.length(), | |
151 &bytes_read)) { | |
152 OnReadCompleted(&request_, bytes_read); | |
153 } | |
154 } | |
155 | |
156 void HttpPipeliningCompatibilityClient::Request::DoReadFinished() { | |
157 if (response_.length() != info_.expected_response.length()) { | |
158 if (info_.expected_response.find(response_) == 0) { | |
159 Finished(TOO_SMALL); | |
160 } else { | |
161 Finished(CONTENT_MISMATCH); | |
162 } | |
163 } else if (response_ == info_.expected_response) { | |
164 Finished(SUCCESS); | |
165 } else { | |
166 Finished(CONTENT_MISMATCH); | |
167 } | |
168 } | |
169 | |
170 void HttpPipeliningCompatibilityClient::Request::Finished(Status result) { | |
171 if (finished_) { | |
172 return; | |
173 } | |
174 finished_ = true; | |
175 const net::URLRequestStatus& status = request_.status(); | |
176 if (status.status() == net::URLRequestStatus::FAILED) { | |
177 // Network errors trump all other status codes, because network errors can | |
178 // be detected by the network stack even with real content. If we determine | |
179 // that all pipelining errors can be detected by the network stack, then we | |
180 // don't need to worry about broken proxies. | |
181 client_->ReportNetworkError(request_id_, status.error()); | |
182 client_->OnRequestFinished(request_id_, NETWORK_ERROR); | |
183 return; | |
184 } | |
185 client_->OnRequestFinished(request_id_, result); | |
186 } | |
187 | |
188 } // namespace chrome_browser_net | |
OLD | NEW |