OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/http/http_proxy_client_socket.h" | 5 #include "net/http/http_proxy_client_socket.h" |
6 | 6 |
7 #include "base/string_util.h" | 7 #include "base/string_util.h" |
8 #include "base/stringprintf.h" | 8 #include "base/stringprintf.h" |
9 #include "googleurl/src/gurl.h" | 9 #include "googleurl/src/gurl.h" |
10 #include "net/base/auth.h" | 10 #include "net/base/auth.h" |
(...skipping 19 matching lines...) Expand all Loading... |
30 const HostPortPair& endpoint, | 30 const HostPortPair& endpoint, |
31 const HostPortPair& proxy_server, | 31 const HostPortPair& proxy_server, |
32 HttpAuthCache* http_auth_cache, | 32 HttpAuthCache* http_auth_cache, |
33 HttpAuthHandlerFactory* http_auth_handler_factory, | 33 HttpAuthHandlerFactory* http_auth_handler_factory, |
34 bool tunnel, | 34 bool tunnel, |
35 bool using_spdy, | 35 bool using_spdy, |
36 bool is_https_proxy) | 36 bool is_https_proxy) |
37 : ALLOW_THIS_IN_INITIALIZER_LIST( | 37 : ALLOW_THIS_IN_INITIALIZER_LIST( |
38 io_callback_(this, &HttpProxyClientSocket::OnIOComplete)), | 38 io_callback_(this, &HttpProxyClientSocket::OnIOComplete)), |
39 next_state_(STATE_NONE), | 39 next_state_(STATE_NONE), |
40 old_user_callback_(NULL), | |
41 transport_(transport_socket), | 40 transport_(transport_socket), |
42 endpoint_(endpoint), | 41 endpoint_(endpoint), |
43 auth_(tunnel ? | 42 auth_(tunnel ? |
44 new HttpAuthController(HttpAuth::AUTH_PROXY, | 43 new HttpAuthController(HttpAuth::AUTH_PROXY, |
45 GURL((is_https_proxy ? "https://" : "http://") | 44 GURL((is_https_proxy ? "https://" : "http://") |
46 + proxy_server.ToString()), | 45 + proxy_server.ToString()), |
47 http_auth_cache, | 46 http_auth_cache, |
48 http_auth_handler_factory) | 47 http_auth_handler_factory) |
49 : NULL), | 48 : NULL), |
50 tunnel_(tunnel), | 49 tunnel_(tunnel), |
51 using_spdy_(using_spdy), | 50 using_spdy_(using_spdy), |
52 is_https_proxy_(is_https_proxy), | 51 is_https_proxy_(is_https_proxy), |
53 net_log_(transport_socket->socket()->NetLog()) { | 52 net_log_(transport_socket->socket()->NetLog()) { |
54 // Synthesize the bits of a request that we actually use. | 53 // Synthesize the bits of a request that we actually use. |
55 request_.url = request_url; | 54 request_.url = request_url; |
56 request_.method = "GET"; | 55 request_.method = "GET"; |
57 if (!user_agent.empty()) | 56 if (!user_agent.empty()) |
58 request_.extra_headers.SetHeader(HttpRequestHeaders::kUserAgent, | 57 request_.extra_headers.SetHeader(HttpRequestHeaders::kUserAgent, |
59 user_agent); | 58 user_agent); |
60 } | 59 } |
61 | 60 |
62 HttpProxyClientSocket::~HttpProxyClientSocket() { | 61 HttpProxyClientSocket::~HttpProxyClientSocket() { |
63 Disconnect(); | 62 Disconnect(); |
64 } | 63 } |
65 | 64 |
66 int HttpProxyClientSocket::RestartWithAuth(OldCompletionCallback* callback) { | 65 int HttpProxyClientSocket::RestartWithAuth(OldCompletionCallback* callback) { |
67 DCHECK_EQ(STATE_NONE, next_state_); | 66 DCHECK_EQ(STATE_NONE, next_state_); |
68 DCHECK(!old_user_callback_ && user_callback_.is_null()); | 67 DCHECK(user_callback_.is_null()); |
69 | 68 |
70 int rv = PrepareForAuthRestart(); | 69 int rv = PrepareForAuthRestart(); |
71 if (rv != OK || next_state_ == STATE_NONE) | 70 if (rv != OK || next_state_ == STATE_NONE) |
72 return rv; | 71 return rv; |
73 | 72 |
74 rv = DoLoop(OK); | 73 rv = DoLoop(OK); |
75 if (rv == ERR_IO_PENDING) | 74 if (rv == ERR_IO_PENDING) |
76 old_user_callback_ = callback; | 75 if (callback) { |
| 76 user_callback_ = base::Bind(&OldCompletionCallback::Run<int>, |
| 77 base::Unretained(callback)); |
| 78 } |
77 return rv; | 79 return rv; |
78 } | 80 } |
79 | 81 |
80 const | 82 const |
81 scoped_refptr<HttpAuthController>& HttpProxyClientSocket::auth_controller() { | 83 scoped_refptr<HttpAuthController>& HttpProxyClientSocket::auth_controller() { |
82 return auth_; | 84 return auth_; |
83 } | 85 } |
84 | 86 |
85 const HttpResponseInfo* HttpProxyClientSocket::GetConnectResponseInfo() const { | 87 const HttpResponseInfo* HttpProxyClientSocket::GetConnectResponseInfo() const { |
86 return response_.headers ? &response_ : NULL; | 88 return response_.headers ? &response_ : NULL; |
87 } | 89 } |
88 | 90 |
89 HttpStream* HttpProxyClientSocket::CreateConnectResponseStream() { | 91 HttpStream* HttpProxyClientSocket::CreateConnectResponseStream() { |
90 return new HttpBasicStream(transport_.release(), | 92 return new HttpBasicStream(transport_.release(), |
91 http_stream_parser_.release(), false); | 93 http_stream_parser_.release(), false); |
92 } | 94 } |
93 | 95 |
94 | 96 |
95 int HttpProxyClientSocket::Connect(OldCompletionCallback* callback) { | |
96 DCHECK(transport_.get()); | |
97 DCHECK(transport_->socket()); | |
98 DCHECK(!old_user_callback_ && user_callback_.is_null()); | |
99 | |
100 // TODO(rch): figure out the right way to set up a tunnel with SPDY. | |
101 // This approach sends the complete HTTPS request to the proxy | |
102 // which allows the proxy to see "private" data. Instead, we should | |
103 // create an SSL tunnel to the origin server using the CONNECT method | |
104 // inside a single SPDY stream. | |
105 if (using_spdy_ || !tunnel_) | |
106 next_state_ = STATE_DONE; | |
107 if (next_state_ == STATE_DONE) | |
108 return OK; | |
109 | |
110 DCHECK_EQ(STATE_NONE, next_state_); | |
111 next_state_ = STATE_GENERATE_AUTH_TOKEN; | |
112 | |
113 int rv = DoLoop(OK); | |
114 if (rv == ERR_IO_PENDING) | |
115 old_user_callback_ = callback; | |
116 return rv; | |
117 } | |
118 | |
119 int HttpProxyClientSocket::Connect(const CompletionCallback& callback) { | 97 int HttpProxyClientSocket::Connect(const CompletionCallback& callback) { |
120 DCHECK(transport_.get()); | 98 DCHECK(transport_.get()); |
121 DCHECK(transport_->socket()); | 99 DCHECK(transport_->socket()); |
122 DCHECK(!old_user_callback_ && user_callback_.is_null()); | 100 DCHECK(user_callback_.is_null()); |
123 | 101 |
124 // TODO(rch): figure out the right way to set up a tunnel with SPDY. | 102 // TODO(rch): figure out the right way to set up a tunnel with SPDY. |
125 // This approach sends the complete HTTPS request to the proxy | 103 // This approach sends the complete HTTPS request to the proxy |
126 // which allows the proxy to see "private" data. Instead, we should | 104 // which allows the proxy to see "private" data. Instead, we should |
127 // create an SSL tunnel to the origin server using the CONNECT method | 105 // create an SSL tunnel to the origin server using the CONNECT method |
128 // inside a single SPDY stream. | 106 // inside a single SPDY stream. |
129 if (using_spdy_ || !tunnel_) | 107 if (using_spdy_ || !tunnel_) |
130 next_state_ = STATE_DONE; | 108 next_state_ = STATE_DONE; |
131 if (next_state_ == STATE_DONE) | 109 if (next_state_ == STATE_DONE) |
132 return OK; | 110 return OK; |
133 | 111 |
134 DCHECK_EQ(STATE_NONE, next_state_); | 112 DCHECK_EQ(STATE_NONE, next_state_); |
135 next_state_ = STATE_GENERATE_AUTH_TOKEN; | 113 next_state_ = STATE_GENERATE_AUTH_TOKEN; |
136 | 114 |
137 int rv = DoLoop(OK); | 115 int rv = DoLoop(OK); |
138 if (rv == ERR_IO_PENDING) | 116 if (rv == ERR_IO_PENDING) |
139 user_callback_ = callback; | 117 user_callback_ = callback; |
140 return rv; | 118 return rv; |
141 } | 119 } |
142 | 120 |
143 void HttpProxyClientSocket::Disconnect() { | 121 void HttpProxyClientSocket::Disconnect() { |
144 if (transport_.get()) | 122 if (transport_.get()) |
145 transport_->socket()->Disconnect(); | 123 transport_->socket()->Disconnect(); |
146 | 124 |
147 // Reset other states to make sure they aren't mistakenly used later. | 125 // Reset other states to make sure they aren't mistakenly used later. |
148 // These are the states initialized by Connect(). | 126 // These are the states initialized by Connect(). |
149 next_state_ = STATE_NONE; | 127 next_state_ = STATE_NONE; |
150 old_user_callback_ = NULL; | |
151 user_callback_.Reset(); | 128 user_callback_.Reset(); |
152 } | 129 } |
153 | 130 |
154 bool HttpProxyClientSocket::IsConnected() const { | 131 bool HttpProxyClientSocket::IsConnected() const { |
155 return next_state_ == STATE_DONE && transport_->socket()->IsConnected(); | 132 return next_state_ == STATE_DONE && transport_->socket()->IsConnected(); |
156 } | 133 } |
157 | 134 |
158 bool HttpProxyClientSocket::IsConnectedAndIdle() const { | 135 bool HttpProxyClientSocket::IsConnectedAndIdle() const { |
159 return next_state_ == STATE_DONE && | 136 return next_state_ == STATE_DONE && |
160 transport_->socket()->IsConnectedAndIdle(); | 137 transport_->socket()->IsConnectedAndIdle(); |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
206 | 183 |
207 base::TimeDelta HttpProxyClientSocket::GetConnectTimeMicros() const { | 184 base::TimeDelta HttpProxyClientSocket::GetConnectTimeMicros() const { |
208 if (transport_.get() && transport_->socket()) { | 185 if (transport_.get() && transport_->socket()) { |
209 return transport_->socket()->GetConnectTimeMicros(); | 186 return transport_->socket()->GetConnectTimeMicros(); |
210 } | 187 } |
211 NOTREACHED(); | 188 NOTREACHED(); |
212 return base::TimeDelta::FromMicroseconds(-1); | 189 return base::TimeDelta::FromMicroseconds(-1); |
213 } | 190 } |
214 | 191 |
215 int HttpProxyClientSocket::Read(IOBuffer* buf, int buf_len, | 192 int HttpProxyClientSocket::Read(IOBuffer* buf, int buf_len, |
216 OldCompletionCallback* callback) { | 193 const CompletionCallback& callback) { |
217 DCHECK(!old_user_callback_ && user_callback_.is_null()); | 194 DCHECK(user_callback_.is_null()); |
218 if (next_state_ != STATE_DONE) { | 195 if (next_state_ != STATE_DONE) { |
219 // We're trying to read the body of the response but we're still trying | 196 // We're trying to read the body of the response but we're still trying |
220 // to establish an SSL tunnel through the proxy. We can't read these | 197 // to establish an SSL tunnel through the proxy. We can't read these |
221 // bytes when establishing a tunnel because they might be controlled by | |
222 // an active network attacker. We don't worry about this for HTTP | |
223 // because an active network attacker can already control HTTP sessions. | |
224 // We reach this case when the user cancels a 407 proxy auth prompt. | |
225 // See http://crbug.com/8473. | |
226 DCHECK_EQ(407, response_.headers->response_code()); | |
227 LogBlockedTunnelResponse(response_.headers->response_code()); | |
228 | |
229 return ERR_TUNNEL_CONNECTION_FAILED; | |
230 } | |
231 | |
232 return transport_->socket()->Read(buf, buf_len, callback); | |
233 } | |
234 int HttpProxyClientSocket::Read(IOBuffer* buf, int buf_len, | |
235 const CompletionCallback& callback) { | |
236 DCHECK(!old_user_callback_ && user_callback_.is_null()); | |
237 if (next_state_ != STATE_DONE) { | |
238 // We're trying to read the body of the response but we're still trying | |
239 // to establish an SSL tunnel through the proxy. We can't read these | |
240 // bytes when establishing a tunnel because they might be controlled by | 198 // bytes when establishing a tunnel because they might be controlled by |
241 // an active network attacker. We don't worry about this for HTTP | 199 // an active network attacker. We don't worry about this for HTTP |
242 // because an active network attacker can already control HTTP sessions. | 200 // because an active network attacker can already control HTTP sessions. |
243 // We reach this case when the user cancels a 407 proxy auth prompt. | 201 // We reach this case when the user cancels a 407 proxy auth prompt. |
244 // See http://crbug.com/8473. | 202 // See http://crbug.com/8473. |
245 DCHECK_EQ(407, response_.headers->response_code()); | 203 DCHECK_EQ(407, response_.headers->response_code()); |
246 LogBlockedTunnelResponse(response_.headers->response_code()); | 204 LogBlockedTunnelResponse(response_.headers->response_code()); |
247 | 205 |
248 return ERR_TUNNEL_CONNECTION_FAILED; | 206 return ERR_TUNNEL_CONNECTION_FAILED; |
249 } | 207 } |
250 | 208 |
251 return transport_->socket()->Read(buf, buf_len, callback); | 209 return transport_->socket()->Read(buf, buf_len, callback); |
252 } | 210 } |
253 | 211 |
254 int HttpProxyClientSocket::Write(IOBuffer* buf, int buf_len, | 212 int HttpProxyClientSocket::Write(IOBuffer* buf, int buf_len, |
255 OldCompletionCallback* callback) { | 213 const CompletionCallback& callback) { |
256 DCHECK_EQ(STATE_DONE, next_state_); | 214 DCHECK_EQ(STATE_DONE, next_state_); |
257 DCHECK(!old_user_callback_); | 215 DCHECK(user_callback_.is_null()); |
258 | 216 |
259 return transport_->socket()->Write(buf, buf_len, callback); | 217 return transport_->socket()->Write(buf, buf_len, callback); |
260 } | 218 } |
261 | 219 |
262 bool HttpProxyClientSocket::SetReceiveBufferSize(int32 size) { | 220 bool HttpProxyClientSocket::SetReceiveBufferSize(int32 size) { |
263 return transport_->socket()->SetReceiveBufferSize(size); | 221 return transport_->socket()->SetReceiveBufferSize(size); |
264 } | 222 } |
265 | 223 |
266 bool HttpProxyClientSocket::SetSendBufferSize(int32 size) { | 224 bool HttpProxyClientSocket::SetSendBufferSize(int32 size) { |
267 return transport_->socket()->SetSendBufferSize(size); | 225 return transport_->socket()->SetSendBufferSize(size); |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
314 } | 272 } |
315 | 273 |
316 void HttpProxyClientSocket::LogBlockedTunnelResponse(int response_code) const { | 274 void HttpProxyClientSocket::LogBlockedTunnelResponse(int response_code) const { |
317 LOG(WARNING) << "Blocked proxy response with status " << response_code | 275 LOG(WARNING) << "Blocked proxy response with status " << response_code |
318 << " to CONNECT request for " | 276 << " to CONNECT request for " |
319 << GetHostAndPort(request_.url) << "."; | 277 << GetHostAndPort(request_.url) << "."; |
320 } | 278 } |
321 | 279 |
322 void HttpProxyClientSocket::DoCallback(int result) { | 280 void HttpProxyClientSocket::DoCallback(int result) { |
323 DCHECK_NE(ERR_IO_PENDING, result); | 281 DCHECK_NE(ERR_IO_PENDING, result); |
324 DCHECK(old_user_callback_ || !user_callback_.is_null()); | 282 DCHECK(!user_callback_.is_null()); |
325 | 283 |
326 // Since Run() may result in Read being called, | 284 // Since Run() may result in Read being called, |
327 // clear old_user_callback_ up front. | 285 // clear user_callback_ up front. |
328 if (old_user_callback_) { | 286 CompletionCallback c = user_callback_; |
329 OldCompletionCallback* c = old_user_callback_; | 287 user_callback_.Reset(); |
330 old_user_callback_ = NULL; | 288 c.Run(result); |
331 c->Run(result); | |
332 } else { | |
333 CompletionCallback c = user_callback_; | |
334 user_callback_.Reset(); | |
335 c.Run(result); | |
336 } | |
337 } | 289 } |
338 | 290 |
339 void HttpProxyClientSocket::OnIOComplete(int result) { | 291 void HttpProxyClientSocket::OnIOComplete(int result) { |
340 DCHECK_NE(STATE_NONE, next_state_); | 292 DCHECK_NE(STATE_NONE, next_state_); |
341 DCHECK_NE(STATE_DONE, next_state_); | 293 DCHECK_NE(STATE_DONE, next_state_); |
342 int rv = DoLoop(result); | 294 int rv = DoLoop(result); |
343 if (rv != ERR_IO_PENDING) | 295 if (rv != ERR_IO_PENDING) |
344 DoCallback(rv); | 296 DoCallback(rv); |
345 } | 297 } |
346 | 298 |
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
516 | 468 |
517 if (http_stream_parser_->IsResponseBodyComplete()) | 469 if (http_stream_parser_->IsResponseBodyComplete()) |
518 return DidDrainBodyForAuthRestart(true); | 470 return DidDrainBodyForAuthRestart(true); |
519 | 471 |
520 // Keep draining. | 472 // Keep draining. |
521 next_state_ = STATE_DRAIN_BODY; | 473 next_state_ = STATE_DRAIN_BODY; |
522 return OK; | 474 return OK; |
523 } | 475 } |
524 | 476 |
525 } // namespace net | 477 } // namespace net |
OLD | NEW |