Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(214)

Side by Side Diff: net/http/http_transaction_winhttp.cc

Issue 17635: Remove HttpTransactionWinHttp and the --winhttp command-line... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « net/http/http_transaction_winhttp.h ('k') | net/http/http_transaction_winhttp_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2006-2008 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 "net/http/http_transaction_winhttp.h"
6
7 #include <winhttp.h>
8
9 #include "base/lock.h"
10 #include "base/memory_debug.h"
11 #include "base/message_loop.h"
12 #include "base/string_piece.h"
13 #include "base/string_util.h"
14 #include "base/sys_string_conversions.h"
15 #include "googleurl/src/gurl.h"
16 #include "net/base/auth_cache.h"
17 #include "net/base/cert_status_flags.h"
18 #include "net/base/dns_resolution_observer.h"
19 #include "net/base/load_flags.h"
20 #include "net/base/net_errors.h"
21 #include "net/base/net_util.h"
22 #include "net/base/ssl_config_service.h"
23 #include "net/base/upload_data_stream.h"
24 #include "net/http/cert_status_cache.h"
25 #include "net/http/http_request_info.h"
26 #include "net/http/winhttp_request_throttle.h"
27 #include "net/proxy/proxy_resolver_winhttp.h"
28
29 #pragma comment(lib, "winhttp.lib")
30 #pragma warning(disable: 4355)
31
32 using base::Time;
33
34 namespace net {
35
36 static int TranslateOSError(DWORD error) {
37 switch (error) {
38 case ERROR_SUCCESS:
39 return OK;
40 case ERROR_FILE_NOT_FOUND:
41 return ERR_FILE_NOT_FOUND;
42 case ERROR_HANDLE_EOF: // TODO(wtc): return OK?
43 return ERR_CONNECTION_CLOSED;
44 case ERROR_INVALID_HANDLE:
45 return ERR_INVALID_HANDLE;
46 case ERROR_INVALID_PARAMETER:
47 return ERR_INVALID_ARGUMENT;
48
49 case ERROR_WINHTTP_CANNOT_CONNECT:
50 return ERR_CONNECTION_FAILED;
51 case ERROR_WINHTTP_TIMEOUT:
52 return ERR_TIMED_OUT;
53 case ERROR_WINHTTP_INVALID_URL:
54 return ERR_INVALID_URL;
55 case ERROR_WINHTTP_NAME_NOT_RESOLVED:
56 return ERR_NAME_NOT_RESOLVED;
57 case ERROR_WINHTTP_OPERATION_CANCELLED:
58 return ERR_ABORTED;
59 case ERROR_WINHTTP_SECURE_CHANNEL_ERROR:
60 case ERROR_WINHTTP_SECURE_FAILURE:
61 case SEC_E_ILLEGAL_MESSAGE:
62 return ERR_SSL_PROTOCOL_ERROR;
63 case SEC_E_ALGORITHM_MISMATCH:
64 return ERR_SSL_VERSION_OR_CIPHER_MISMATCH;
65 case ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED:
66 return ERR_SSL_CLIENT_AUTH_CERT_NEEDED;
67 case ERROR_WINHTTP_UNRECOGNIZED_SCHEME:
68 return ERR_UNKNOWN_URL_SCHEME;
69 case ERROR_WINHTTP_INVALID_SERVER_RESPONSE:
70 return ERR_INVALID_RESPONSE;
71
72 // SSL certificate errors
73 case ERROR_WINHTTP_SECURE_CERT_CN_INVALID:
74 return ERR_CERT_COMMON_NAME_INVALID;
75 case ERROR_WINHTTP_SECURE_CERT_DATE_INVALID:
76 return ERR_CERT_DATE_INVALID;
77 case ERROR_WINHTTP_SECURE_INVALID_CA:
78 return ERR_CERT_AUTHORITY_INVALID;
79 case ERROR_WINHTTP_SECURE_CERT_REV_FAILED:
80 return ERR_CERT_UNABLE_TO_CHECK_REVOCATION;
81 case ERROR_WINHTTP_SECURE_CERT_REVOKED:
82 return ERR_CERT_REVOKED;
83 case ERROR_WINHTTP_SECURE_INVALID_CERT:
84 return ERR_CERT_INVALID;
85
86 default:
87 DCHECK(error != ERROR_IO_PENDING); // WinHTTP doesn't use this error.
88 LOG(WARNING) << "Unknown error " << error
89 << " mapped to net::ERR_FAILED";
90 return ERR_FAILED;
91 }
92 }
93
94 static int TranslateLastOSError() {
95 return TranslateOSError(GetLastError());
96 }
97
98 // Clear certificate errors that we want to ignore.
99 static DWORD FilterSecureFailure(DWORD status, int load_flags) {
100 if (load_flags & LOAD_IGNORE_CERT_COMMON_NAME_INVALID)
101 status &= ~WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID;
102 if (load_flags & LOAD_IGNORE_CERT_DATE_INVALID)
103 status &= ~WINHTTP_CALLBACK_STATUS_FLAG_CERT_DATE_INVALID;
104 if (load_flags & LOAD_IGNORE_CERT_AUTHORITY_INVALID)
105 status &= ~WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA;
106 if (load_flags & LOAD_IGNORE_CERT_WRONG_USAGE)
107 status &= ~WINHTTP_CALLBACK_STATUS_FLAG_CERT_WRONG_USAGE;
108 return status;
109 }
110
111 static DWORD MapSecureFailureToError(DWORD status) {
112 // A certificate may have multiple errors. We report the most
113 // serious error.
114
115 // Unrecoverable errors
116 if (status & WINHTTP_CALLBACK_STATUS_FLAG_SECURITY_CHANNEL_ERROR)
117 return ERROR_WINHTTP_SECURE_CHANNEL_ERROR;
118 if (status & WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CERT)
119 return ERROR_WINHTTP_SECURE_INVALID_CERT;
120 if (status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_REVOKED)
121 return ERROR_WINHTTP_SECURE_CERT_REVOKED;
122
123 // Recoverable errors
124 if (status & WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA)
125 return ERROR_WINHTTP_SECURE_INVALID_CA;
126 if (status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID)
127 return ERROR_WINHTTP_SECURE_CERT_CN_INVALID;
128 if (status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_DATE_INVALID)
129 return ERROR_WINHTTP_SECURE_CERT_DATE_INVALID;
130 if (status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_WRONG_USAGE)
131 return ERROR_WINHTTP_SECURE_CERT_WRONG_USAGE;
132
133 // Unknown status. Give it the benefit of the doubt.
134 if (status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_REV_FAILED)
135 return ERROR_WINHTTP_SECURE_CERT_REV_FAILED;
136
137 // Map a status of 0 to the generic secure failure error. We have seen a
138 // case where WinHttp doesn't notify us of a secure failure (so status is 0)
139 // before notifying us of a request error with ERROR_WINHTTP_SECURE_FAILURE.
140 // (WinInet fails with ERROR_INTERNET_SECURITY_CHANNEL_ERROR in that case.)
141 return ERROR_WINHTTP_SECURE_FAILURE;
142 }
143
144 static int MapSecureFailureToCertStatus(DWORD status) {
145 int cert_status = 0;
146
147 if (status & WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CERT)
148 cert_status |= CERT_STATUS_INVALID;
149 if (status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_REVOKED)
150 cert_status |= CERT_STATUS_REVOKED;
151 if (status & WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA)
152 cert_status |= CERT_STATUS_AUTHORITY_INVALID;
153 if (status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID)
154 cert_status |= CERT_STATUS_COMMON_NAME_INVALID;
155 if (status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_DATE_INVALID)
156 cert_status |= CERT_STATUS_DATE_INVALID;
157 if (status & WINHTTP_CALLBACK_STATUS_FLAG_CERT_REV_FAILED)
158 cert_status |= CERT_STATUS_UNABLE_TO_CHECK_REVOCATION;
159
160 return cert_status;
161 // TODO(jcampan): what about ERROR_WINHTTP_SECURE_CERT_WRONG_USAGE?
162 }
163
164 // Session --------------------------------------------------------------------
165
166 class HttpTransactionWinHttp::Session
167 : public base::RefCounted<HttpTransactionWinHttp::Session> {
168 public:
169 enum {
170 // By default WinHTTP enables only SSL3 and TLS1.
171 SECURE_PROTOCOLS_SSL3_TLS1 = WINHTTP_FLAG_SECURE_PROTOCOL_SSL3 |
172 WINHTTP_FLAG_SECURE_PROTOCOL_TLS1
173 };
174
175 explicit Session(ProxyService* proxy_service);
176
177 // Opens the primary WinHttp session handle.
178 bool Init(const std::string& user_agent);
179
180 // Opens the alternative WinHttp session handle for TLS-intolerant servers.
181 bool InitNoTLS(const std::string& user_agent);
182
183 void AddRefBySessionCallback();
184
185 void ReleaseBySessionCallback();
186
187 // The primary WinHttp session handle.
188 HINTERNET internet() { return internet_; }
189
190 // An alternative WinHttp session handle. It is not opened until we have
191 // encountered a TLS-intolerant server and used for those servers only.
192 // TLS is disabled in this session.
193 HINTERNET internet_no_tls() { return internet_no_tls_; }
194
195 // The message loop of the thread where the session was created.
196 MessageLoop* message_loop() { return message_loop_; }
197
198 ProxyService* proxy_service() { return proxy_service_; }
199
200 // Gets the HTTP authentication cache for the session.
201 AuthCache* auth_cache() { return &auth_cache_; }
202
203 HANDLE handle_closing_event() const { return handle_closing_event_; }
204
205 CertStatusCache* cert_status_cache() { return &cert_status_cache_; }
206
207 bool rev_checking_enabled() const { return rev_checking_enabled_; }
208
209 bool tls_enabled() const {
210 return (secure_protocols_ & WINHTTP_FLAG_SECURE_PROTOCOL_TLS1) != 0;
211 }
212
213 bool ShouldIgnoreCertRev(const std::string& origin) const {
214 OriginSet::const_iterator pos = ignore_cert_rev_servers_.find(origin);
215 return pos != ignore_cert_rev_servers_.end();
216 }
217
218 void IgnoreCertRev(const std::string& origin) {
219 ignore_cert_rev_servers_.insert(origin);
220 }
221
222 WinHttpRequestThrottle* request_throttle() {
223 return &request_throttle_;
224 }
225
226 private:
227 friend class base::RefCounted<HttpTransactionWinHttp::Session>;
228
229 ~Session();
230
231 // Called by the destructor only.
232 void WaitUntilCallbacksAllDone();
233
234 HINTERNET OpenWinHttpSession(const std::string& user_agent);
235
236 // Get the SSL configuration settings and save them in rev_checking_enabled_
237 // and secure_protocols_.
238 void GetSSLConfig();
239
240 HINTERNET internet_;
241 HINTERNET internet_no_tls_;
242 MessageLoop* message_loop_;
243 ProxyService* proxy_service_;
244 AuthCache auth_cache_;
245
246 // This event object is used when destroying a transaction. It is given
247 // to the transaction's session callback if WinHTTP still has the caller's
248 // data (request info or read buffer) and we need to wait until WinHTTP is
249 // done with the data.
250 HANDLE handle_closing_event_;
251
252 // The following members ensure a clean destruction of the Session object.
253 // The Session destructor waits until all the request handles have been
254 // terminated by WinHTTP, at which point no more status callbacks will
255 // reference the MessageLoop of the Session.
256 //
257 // quit_event_ is the event object used for this wait.
258 //
259 // lock_ protects session_callback_ref_count_ and quitting_.
260 //
261 // session_callback_ref_count_ is the number of SessionCallback objects
262 // that may reference the MessageLoop of the Session.
263 //
264 // The boolean quitting_ is true when the Session object is being
265 // destructed.
266 HANDLE quit_event_;
267 Lock lock_;
268 int session_callback_ref_count_;
269 bool quitting_;
270
271 // We use a cache to store the certificate error as we cannot always rely on
272 // WinHTTP to provide us the SSL error once we restarted a connection asking
273 // to ignored errors.
274 CertStatusCache cert_status_cache_;
275
276 // SSL settings
277 bool rev_checking_enabled_;
278 DWORD secure_protocols_;
279
280 // The servers for which certificate revocation should be ignored.
281 //
282 // WinHTTP verifies each certificate only once and caches the certificate
283 // verification results, so if we ever ignore certificate revocation for a
284 // server, we cannot enable revocation checking again for that server for
285 // the rest of the session.
286 //
287 // If we honor changes to the rev_checking_enabled system setting during
288 // the session, we will have to remember all the servers we have visited
289 // while the rev_checking_enabled setting is false. This will consume a
290 // lot of memory. So we now require the users to restart Chrome for a
291 // rev_checking_enabled change to take effect, just like IE does.
292 typedef std::set<std::string> OriginSet;
293 OriginSet ignore_cert_rev_servers_;
294
295 WinHttpRequestThrottle request_throttle_;
296 };
297
298 HttpTransactionWinHttp::Session::Session(ProxyService* proxy_service)
299 : internet_(NULL),
300 internet_no_tls_(NULL),
301 proxy_service_(proxy_service),
302 session_callback_ref_count_(0),
303 quitting_(false) {
304 GetSSLConfig();
305
306 // Save the current message loop for callback notifications.
307 message_loop_ = MessageLoop::current();
308
309 handle_closing_event_ = CreateEvent(NULL,
310 FALSE, // auto-reset
311 FALSE, // initially nonsignaled
312 NULL); // unnamed
313
314 quit_event_ = CreateEvent(NULL,
315 FALSE, // auto-reset
316 FALSE, // initially nonsignaled
317 NULL); // unnamed
318 }
319
320 HttpTransactionWinHttp::Session::~Session() {
321 if (internet_) {
322 WinHttpCloseHandle(internet_);
323 if (internet_no_tls_)
324 WinHttpCloseHandle(internet_no_tls_);
325
326 // Ensure that all status callbacks that may reference the MessageLoop
327 // of this thread are done before we can allow the current thread to exit.
328 WaitUntilCallbacksAllDone();
329 }
330
331 if (handle_closing_event_)
332 CloseHandle(handle_closing_event_);
333 if (quit_event_)
334 CloseHandle(quit_event_);
335 }
336
337 bool HttpTransactionWinHttp::Session::Init(const std::string& user_agent) {
338 DCHECK(!internet_);
339
340 internet_ = OpenWinHttpSession(user_agent);
341
342 if (!internet_)
343 return false;
344
345 if (secure_protocols_ != SECURE_PROTOCOLS_SSL3_TLS1) {
346 BOOL rv = WinHttpSetOption(internet_, WINHTTP_OPTION_SECURE_PROTOCOLS,
347 &secure_protocols_, sizeof(secure_protocols_));
348 DCHECK(rv);
349 }
350
351 return true;
352 }
353
354 bool HttpTransactionWinHttp::Session::InitNoTLS(
355 const std::string& user_agent) {
356 DCHECK(tls_enabled());
357 DCHECK(internet_);
358 DCHECK(!internet_no_tls_);
359
360 internet_no_tls_ = OpenWinHttpSession(user_agent);
361
362 if (!internet_no_tls_)
363 return false;
364
365 DWORD protocols = secure_protocols_ & ~WINHTTP_FLAG_SECURE_PROTOCOL_TLS1;
366 BOOL rv = WinHttpSetOption(internet_no_tls_,
367 WINHTTP_OPTION_SECURE_PROTOCOLS,
368 &protocols, sizeof(protocols));
369 DCHECK(rv);
370
371 return true;
372 }
373
374 void HttpTransactionWinHttp::Session::AddRefBySessionCallback() {
375 AutoLock lock(lock_);
376 session_callback_ref_count_++;
377 }
378
379 void HttpTransactionWinHttp::Session::ReleaseBySessionCallback() {
380 bool need_to_signal;
381 {
382 AutoLock lock(lock_);
383 session_callback_ref_count_--;
384 need_to_signal = (quitting_ && session_callback_ref_count_ == 0);
385 }
386 if (need_to_signal)
387 SetEvent(quit_event_);
388 }
389
390 // This is called by the Session destructor only. By now the transaction
391 // factory and all the transactions have been destructed. This means that
392 // new transactions can't be created, and existing transactions can't be
393 // started, which in turn implies that session_callback_ref_count_ cannot
394 // increase. We wait until session_callback_ref_count_ drops to 0.
395 void HttpTransactionWinHttp::Session::WaitUntilCallbacksAllDone() {
396 bool need_to_wait;
397 {
398 AutoLock lock(lock_);
399 quitting_ = true;
400 need_to_wait = (session_callback_ref_count_ != 0);
401 }
402 if (need_to_wait)
403 WaitForSingleObject(quit_event_, INFINITE);
404 DCHECK(session_callback_ref_count_ == 0);
405 }
406
407 HINTERNET HttpTransactionWinHttp::Session::OpenWinHttpSession(
408 const std::string& user_agent) {
409 // Proxy config will be set explicitly for each request.
410 //
411 // Although UA string will also be set explicitly for each request, HTTP
412 // CONNECT requests use the UA string of the session handle, so we have to
413 // pass a UA string to WinHttpOpen.
414 HINTERNET internet = WinHttpOpen(ASCIIToWide(user_agent).c_str(),
415 WINHTTP_ACCESS_TYPE_NO_PROXY,
416 WINHTTP_NO_PROXY_NAME,
417 WINHTTP_NO_PROXY_BYPASS,
418 WINHTTP_FLAG_ASYNC);
419 if (!internet)
420 return internet;
421
422 // Use a 90-second timeout (1.5 times the default) for connect. Disable
423 // name resolution, send, and receive timeouts. We expect our consumer to
424 // apply timeouts or provide controls for users to stop requests that are
425 // taking too long.
426 BOOL rv = WinHttpSetTimeouts(internet, 0, 90000, 0, 0);
427 DCHECK(rv);
428
429 return internet;
430 }
431
432 void HttpTransactionWinHttp::Session::GetSSLConfig() {
433 SSLConfig ssl_config;
434 SSLConfigService::GetSSLConfigNow(&ssl_config);
435 rev_checking_enabled_ = ssl_config.rev_checking_enabled;
436 secure_protocols_ = 0;
437 if (ssl_config.ssl2_enabled)
438 secure_protocols_ |= WINHTTP_FLAG_SECURE_PROTOCOL_SSL2;
439 if (ssl_config.ssl3_enabled)
440 secure_protocols_ |= WINHTTP_FLAG_SECURE_PROTOCOL_SSL3;
441 if (ssl_config.tls1_enabled)
442 secure_protocols_ |= WINHTTP_FLAG_SECURE_PROTOCOL_TLS1;
443 }
444
445 // SessionCallback ------------------------------------------------------------
446
447 class HttpTransactionWinHttp::SessionCallback
448 : public base::RefCountedThreadSafe<HttpTransactionWinHttp::SessionCallback> {
449 public:
450 SessionCallback(HttpTransactionWinHttp* trans, Session* session)
451 : trans_(trans),
452 session_(session),
453 load_state_(LOAD_STATE_IDLE),
454 handle_closing_event_(NULL),
455 bytes_available_(0),
456 read_buf_(NULL),
457 read_buf_len_(0),
458 secure_failure_(0),
459 connection_was_opened_(false),
460 request_was_probably_sent_(false),
461 response_was_received_(false),
462 response_is_empty_(true) {
463 }
464
465 // Called when the associated trans_ has to reopen its connection and
466 // request handles to recover from certain SSL errors. Resets the members
467 // that may have been modified at that point.
468 void ResetForNewRequest() {
469 secure_failure_ = 0;
470 connection_was_opened_ = false;
471 }
472
473 void DropTransaction() {
474 trans_ = NULL;
475 }
476
477 void Notify(DWORD status, DWORD_PTR result, DWORD error) {
478 DWORD secure_failure = 0;
479 if (status == WINHTTP_CALLBACK_STATUS_REQUEST_ERROR) {
480 switch (error) {
481 // WinHttp sends this error code in two interesting cases: 1) when a
482 // response header is malformed, and 2) when a response is empty. In
483 // the latter case, we want to actually resend the request if the
484 // request was sent over a reused "keep-alive" connection. This is a
485 // risky thing to do since it is possible that the server did receive
486 // our request, but it is unfortunately required to support HTTP keep-
487 // alive connections properly, and other browsers all do this too.
488 case ERROR_WINHTTP_INVALID_SERVER_RESPONSE:
489 if (empty_response_was_received() && !connection_was_opened_)
490 error = ERROR_WINHTTP_RESEND_REQUEST;
491 break;
492 case ERROR_WINHTTP_SECURE_FAILURE:
493 secure_failure = secure_failure_;
494 break;
495 }
496 } else if (status == WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE) {
497 secure_failure = secure_failure_;
498 }
499 session_->message_loop()->PostTask(FROM_HERE,
500 NewRunnableMethod(this,
501 &HttpTransactionWinHttp::SessionCallback::OnNotify,
502 status, result, error, secure_failure));
503 }
504
505 // Calls WinHttpReadData and returns its return value.
506 BOOL ReadData(HINTERNET request_handle);
507
508 void OnHandleClosing() {
509 if (handle_closing_event_)
510 SetEvent(handle_closing_event_);
511 session_->ReleaseBySessionCallback();
512 Release();
513 }
514
515 // Modified from any thread.
516 void set_load_state(LoadState state) {
517 load_state_ = state;
518 }
519 LoadState load_state() const {
520 return load_state_;
521 }
522
523 int bytes_available() const { return bytes_available_; }
524 void set_bytes_available(int n) { bytes_available_ = n; }
525 void reduce_bytes_available(int n) { bytes_available_ -= n; }
526
527 char* read_buf() const { return read_buf_; }
528 void set_read_buf(char* buf) { read_buf_ = buf; }
529
530 int read_buf_len() const { return read_buf_len_; }
531 void set_read_buf_len(int buf_len) { read_buf_len_ = buf_len; }
532
533 // Tells this SessionCallback to signal this event when receiving the
534 // handle closing status callback.
535 void set_handle_closing_event(HANDLE event) {
536 handle_closing_event_ = event;
537 }
538
539 void set_secure_failure(DWORD flags) { secure_failure_ = flags; }
540
541 void did_open_connection() {
542 connection_was_opened_ = true;
543 }
544
545 void did_start_sending_request() {
546 request_was_probably_sent_ = true;
547 }
548 bool request_was_probably_sent() const {
549 return request_was_probably_sent_;
550 }
551
552 void did_receive_bytes(DWORD count) {
553 response_was_received_ = true;
554 if (count)
555 response_is_empty_ = false;
556 }
557
558 private:
559 friend base::RefCountedThreadSafe<HttpTransactionWinHttp::SessionCallback>;
560 ~SessionCallback() {}
561
562 void OnNotify(DWORD status,
563 DWORD_PTR result,
564 DWORD error,
565 DWORD secure_failure) {
566 if (trans_)
567 trans_->HandleStatusCallback(status, result, error, secure_failure);
568
569 // Balances the AddRefs made by the transaction object after an async
570 // WinHTTP call.
571 Release();
572 }
573
574 bool empty_response_was_received() const {
575 return response_was_received_ && response_is_empty_;
576 }
577
578 HttpTransactionWinHttp* trans_;
579
580 // Session is reference-counted, but this is a plain pointer. The
581 // reference on the Session owned by SessionCallback is managed using
582 // Session::AddRefBySessionCallback and Session::ReleaseBySessionCallback.
583 Session* session_;
584
585 // Modified from any thread.
586 volatile LoadState load_state_;
587
588 // Amount of data available reported by WinHttpQueryDataAvailable that
589 // haven't been consumed by WinHttpReadData.
590 int bytes_available_;
591
592 // Caller's read buffer and buffer size, to be passed to WinHttpReadData.
593 // These are used by the IO thread and the thread WinHTTP uses to make
594 // status callbacks, but not at the same time.
595 char* read_buf_;
596 int read_buf_len_;
597
598 // If not null, we set this event on receiving the handle closing callback.
599 HANDLE handle_closing_event_;
600
601 // The secure connection failure flags reported by the
602 // WINHTTP_CALLBACK_STATUS_SECURE_FAILURE status callback.
603 DWORD secure_failure_;
604
605 // True if a connection was opened for this request.
606 bool connection_was_opened_;
607
608 // True if the request may have been sent to the server (and therefore we
609 // should not restart the request).
610 bool request_was_probably_sent_;
611
612 // True if any response was received.
613 bool response_was_received_;
614
615 // True if we have an empty response (no headers, no status line, nothing).
616 bool response_is_empty_;
617 };
618
619 BOOL HttpTransactionWinHttp::SessionCallback::ReadData(
620 HINTERNET request_handle) {
621 DCHECK(bytes_available_ >= 0);
622 char* buf = read_buf_;
623 read_buf_ = NULL;
624 int bytes_to_read = std::min(bytes_available_, read_buf_len_);
625 read_buf_len_ = 0;
626 if (!bytes_to_read)
627 bytes_to_read = 1;
628
629 // Because of how WinHTTP fills memory when used asynchronously, Purify isn't
630 // able to detect that it's been initialized, so it scans for 0xcd in the
631 // buffer and reports UMRs (uninitialized memory reads) for those individual
632 // bytes. We override that to avoid the false error reports.
633 // See http://b/issue?id=1173916.
634 base::MemoryDebug::MarkAsInitialized(buf, bytes_to_read);
635 return WinHttpReadData(request_handle, buf, bytes_to_read, NULL);
636 }
637
638 // static
639 void HttpTransactionWinHttp::StatusCallback(HINTERNET handle,
640 DWORD_PTR context,
641 DWORD status,
642 LPVOID status_info,
643 DWORD status_info_len) {
644 SessionCallback* callback = reinterpret_cast<SessionCallback*>(context);
645
646 switch (status) {
647 case WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING:
648 if (callback)
649 callback->OnHandleClosing();
650 break;
651 case WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER:
652 callback->set_load_state(LOAD_STATE_CONNECTING);
653 break;
654 case WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER:
655 callback->did_open_connection();
656 break;
657 case WINHTTP_CALLBACK_STATUS_SENDING_REQUEST:
658 callback->set_load_state(LOAD_STATE_SENDING_REQUEST);
659 callback->did_start_sending_request();
660 break;
661 case WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE:
662 callback->set_load_state(LOAD_STATE_WAITING_FOR_RESPONSE);
663 break;
664 case WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED:
665 callback->did_receive_bytes(*static_cast<DWORD*>(status_info));
666 break;
667 case WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE:
668 DCHECK(callback->bytes_available() == 0);
669 DCHECK(status_info_len == sizeof(DWORD));
670 callback->set_bytes_available(static_cast<DWORD*>(status_info)[0]);
671 if (!callback->ReadData(handle))
672 callback->Notify(WINHTTP_CALLBACK_STATUS_REQUEST_ERROR,
673 API_READ_DATA, GetLastError());
674 break;
675 case WINHTTP_CALLBACK_STATUS_READ_COMPLETE:
676 callback->Notify(status, status_info_len, 0);
677 break;
678 case WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE:
679 DCHECK(status_info_len == sizeof(DWORD));
680 callback->Notify(status, static_cast<DWORD*>(status_info)[0], 0);
681 break;
682 case WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE:
683 callback->Notify(status, TRUE, 0);
684 break;
685 case WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE:
686 callback->Notify(status, TRUE, 0);
687 break;
688 case WINHTTP_CALLBACK_STATUS_REQUEST_ERROR: {
689 WINHTTP_ASYNC_RESULT* result =
690 static_cast<WINHTTP_ASYNC_RESULT*>(status_info);
691 callback->Notify(status, result->dwResult, result->dwError);
692 if (API_SEND_REQUEST == result->dwResult &&
693 ERROR_WINHTTP_NAME_NOT_RESOLVED == result->dwError)
694 DidFinishDnsResolutionWithStatus(false,
695 GURL(), // null referrer URL.
696 reinterpret_cast<void*>(context));
697 break;
698 }
699 // This status callback provides the detailed reason for a secure
700 // failure. We map that to an error code and save it for later use.
701 case WINHTTP_CALLBACK_STATUS_SECURE_FAILURE: {
702 DCHECK(status_info_len == sizeof(DWORD));
703 DWORD* status_ptr = static_cast<DWORD*>(status_info);
704 callback->set_secure_failure(*status_ptr);
705 break;
706 }
707 // Looking up the IP address of a server name. The status_info
708 // parameter contains a pointer to the server name being resolved.
709 case WINHTTP_CALLBACK_STATUS_RESOLVING_NAME: {
710 callback->set_load_state(LOAD_STATE_RESOLVING_HOST);
711 std::wstring wname(static_cast<wchar_t*>(status_info),
712 status_info_len - 1);
713 DidStartDnsResolution(WideToASCII(wname),
714 reinterpret_cast<void*>(context));
715 break;
716 }
717 // Successfully found the IP address of the server.
718 case WINHTTP_CALLBACK_STATUS_NAME_RESOLVED:
719 DidFinishDnsResolutionWithStatus(true,
720 GURL(), // null referrer URL.
721 reinterpret_cast<void*>(context));
722 break;
723 }
724 }
725
726 // Factory --------------------------------------------------------------------
727
728 HttpTransactionWinHttp::Factory::~Factory() {
729 if (session_)
730 session_->Release();
731 }
732
733 HttpTransaction* HttpTransactionWinHttp::Factory::CreateTransaction() {
734 if (is_suspended_)
735 return NULL;
736
737 if (!session_) {
738 session_ = new Session(proxy_service_);
739 session_->AddRef();
740 }
741 return new HttpTransactionWinHttp(session_, proxy_service_->proxy_info());
742 }
743
744 HttpCache* HttpTransactionWinHttp::Factory::GetCache() {
745 return NULL;
746 }
747
748 void HttpTransactionWinHttp::Factory::Suspend(bool suspend) {
749 is_suspended_ = suspend;
750
751 if (is_suspended_ && session_) {
752 session_->Release();
753 session_ = NULL;
754 }
755 }
756
757 // Transaction ----------------------------------------------------------------
758
759 HttpTransactionWinHttp::HttpTransactionWinHttp(Session* session,
760 const ProxyInfo* info)
761 : session_(session),
762 request_(NULL),
763 load_flags_(0),
764 last_error_(ERROR_SUCCESS),
765 content_length_remaining_(-1),
766 pac_request_(NULL),
767 proxy_callback_(this, &HttpTransactionWinHttp::OnProxyInfoAvailable),
768 callback_(NULL),
769 upload_progress_(0),
770 connect_handle_(NULL),
771 request_handle_(NULL),
772 is_https_(false),
773 is_tls_intolerant_(false),
774 rev_checking_enabled_(false),
775 have_proxy_info_(false),
776 need_to_wait_for_handle_closing_(false),
777 request_submitted_(false),
778 used_embedded_credentials_(false) {
779 session->AddRef();
780 session_callback_ = new SessionCallback(this, session);
781 if (info) {
782 proxy_info_.Use(*info);
783 have_proxy_info_ = true;
784 }
785 }
786
787 HttpTransactionWinHttp::~HttpTransactionWinHttp() {
788 if (pac_request_)
789 session_->proxy_service()->CancelPacRequest(pac_request_);
790
791 if (request_handle_) {
792 if (need_to_wait_for_handle_closing_) {
793 session_callback_->set_handle_closing_event(
794 session_->handle_closing_event());
795 }
796 WinHttpCloseHandle(request_handle_);
797 if (need_to_wait_for_handle_closing_)
798 WaitForSingleObject(session_->handle_closing_event(), INFINITE);
799 }
800 if (connect_handle_)
801 WinHttpCloseHandle(connect_handle_);
802
803 if (request_submitted_) {
804 session_->request_throttle()->RemoveRequest(connect_peer_,
805 request_handle_);
806 }
807
808 if (session_callback_) {
809 session_callback_->DropTransaction();
810 session_callback_ = NULL; // Release() reference as side effect.
811 }
812 if (session_)
813 session_->Release();
814 }
815
816 int HttpTransactionWinHttp::Start(const HttpRequestInfo* request_info,
817 CompletionCallback* callback) {
818 DCHECK(request_info);
819 DCHECK(callback);
820
821 // ensure that we only have one asynchronous call at a time.
822 DCHECK(!callback_);
823
824 LOG(INFO) << request_info->method << ": " << request_info->url;
825
826 request_ = request_info;
827 load_flags_ = request_info->load_flags;
828
829 int rv = OK;
830 if (!have_proxy_info_) {
831 // Resolve proxy info.
832 rv = session_->proxy_service()->ResolveProxy(request_->url,
833 &proxy_info_,
834 &proxy_callback_,
835 &pac_request_);
836 if (rv == ERR_IO_PENDING) {
837 session_callback_->set_load_state(
838 LOAD_STATE_RESOLVING_PROXY_FOR_URL);
839 }
840 }
841
842 if (rv == OK)
843 rv = DidResolveProxy(); // calls OpenRequest and SendRequest
844
845 if (rv == ERR_IO_PENDING) {
846 session_callback_->AddRef(); // balanced when callback runs or from
847 // OnProxyInfoAvailable.
848 callback_ = callback;
849 }
850
851 return rv;
852 }
853
854 int HttpTransactionWinHttp::RestartIgnoringLastError(
855 CompletionCallback* callback) {
856 int flags = load_flags_;
857
858 // Depending on the error, we make different adjustments to our load flags.
859 // We DCHECK that we shouldn't already have ignored this error.
860 switch (last_error_) {
861 case ERROR_WINHTTP_SECURE_CERT_CN_INVALID:
862 DCHECK(!(flags & LOAD_IGNORE_CERT_COMMON_NAME_INVALID));
863 flags |= LOAD_IGNORE_CERT_COMMON_NAME_INVALID;
864 break;
865 case ERROR_WINHTTP_SECURE_CERT_DATE_INVALID:
866 DCHECK(!(flags & LOAD_IGNORE_CERT_DATE_INVALID));
867 flags |= LOAD_IGNORE_CERT_DATE_INVALID;
868 break;
869 case ERROR_WINHTTP_SECURE_INVALID_CA:
870 DCHECK(!(flags & LOAD_IGNORE_CERT_AUTHORITY_INVALID));
871 flags |= LOAD_IGNORE_CERT_AUTHORITY_INVALID;
872 break;
873 case ERROR_WINHTTP_SECURE_CERT_WRONG_USAGE:
874 DCHECK(!(flags & LOAD_IGNORE_CERT_WRONG_USAGE));
875 flags |= LOAD_IGNORE_CERT_WRONG_USAGE;
876 break;
877 case ERROR_WINHTTP_SECURE_CERT_REV_FAILED: {
878 DCHECK(!(flags & LOAD_IGNORE_CERT_REVOCATION));
879 flags |= LOAD_IGNORE_CERT_REVOCATION;
880 // WinHTTP doesn't have a SECURITY_FLAG_IGNORE_CERT_REV_FAILED flag
881 // and doesn't let us undo WINHTTP_ENABLE_SSL_REVOCATION. The only
882 // way to ignore this error is to open a new request without enabling
883 // WINHTTP_ENABLE_SSL_REVOCATION.
884 if (!ReopenRequest())
885 return TranslateLastOSError();
886 break;
887 }
888 // We can't instruct WinHttp to recover from these errors. No choice
889 // but to cancel the request.
890 case ERROR_WINHTTP_SECURE_CHANNEL_ERROR:
891 case ERROR_WINHTTP_SECURE_INVALID_CERT:
892 case ERROR_WINHTTP_SECURE_CERT_REVOKED:
893 // We don't knows how to continue from here.
894 default:
895 LOG(ERROR) << "Unable to restart the HTTP transaction ignoring "
896 "the error " << last_error_;
897 return ERR_ABORTED;
898 }
899
900 // Update the load flags to ignore the specified error.
901 load_flags_ = flags;
902
903 return Restart(callback);
904 }
905
906 int HttpTransactionWinHttp::RestartWithAuth(
907 const std::wstring& username,
908 const std::wstring& password,
909 CompletionCallback* callback) {
910 DCHECK(proxy_auth_ && proxy_auth_->state == AUTH_STATE_NEED_AUTH ||
911 server_auth_ && server_auth_->state == AUTH_STATE_NEED_AUTH);
912
913 // Proxy gets set first, then WWW.
914 AuthData* auth =
915 proxy_auth_ && proxy_auth_->state == AUTH_STATE_NEED_AUTH ?
916 proxy_auth_ : server_auth_;
917
918 if (auth) {
919 auth->state = AUTH_STATE_HAVE_AUTH;
920 auth->username = username;
921 auth->password = password;
922 }
923
924 return Restart(callback);
925 }
926
927 // The code common to RestartIgnoringLastError and RestartWithAuth.
928 int HttpTransactionWinHttp::Restart(CompletionCallback* callback) {
929 DCHECK(callback);
930
931 // ensure that we only have one asynchronous call at a time.
932 DCHECK(!callback_);
933
934 int rv = RestartInternal();
935 if (rv != ERR_IO_PENDING)
936 return rv;
937
938 session_callback_->AddRef(); // balanced when callback runs.
939
940 callback_ = callback;
941 return ERR_IO_PENDING;
942 }
943
944 // If HttpTransactionWinHttp needs to restart itself after handling an error,
945 // it calls this method. This method leaves callback_ unchanged. The caller
946 // is responsible for calling session_callback_->AddRef() if this method
947 // returns ERR_IO_PENDING.
948 int HttpTransactionWinHttp::RestartInternal() {
949 content_length_remaining_ = -1;
950 upload_progress_ = 0;
951
952 return SendRequest();
953 }
954
955 // We use WinHttpQueryDataAvailable rather than pure async read to trade
956 // a better latency for a decreased throughput. We'll make more IO calls,
957 // and thus use more CPU for a given transaction by using
958 // WinHttpQueryDataAvailable, but it allows us to get a faster response
959 // time to the app for data, which is more important.
960 int HttpTransactionWinHttp::Read(char* buf, int buf_len,
961 CompletionCallback* callback) {
962 DCHECK(buf);
963 DCHECK(buf_len > 0);
964 DCHECK(callback);
965
966 DCHECK(!callback_);
967 DCHECK(request_handle_);
968
969 // If we have already received the full response, then we know we are done.
970 if (content_length_remaining_ == 0) {
971 LogTransactionMetrics();
972 return 0;
973 }
974
975 session_callback_->set_read_buf(buf);
976 session_callback_->set_read_buf_len(buf_len);
977
978 // We must consume all the available data reported by the previous
979 // WinHttpQueryDataAvailable call before we can call
980 // WinHttpQueryDataAvailable again.
981 BOOL ok;
982 if (session_callback_->bytes_available()) {
983 ok = session_callback_->ReadData(request_handle_);
984 } else {
985 ok = WinHttpQueryDataAvailable(request_handle_, NULL);
986 }
987 if (!ok)
988 return TranslateLastOSError();
989
990 session_callback_->set_load_state(LOAD_STATE_READING_RESPONSE);
991 session_callback_->AddRef(); // balanced when callback runs.
992 need_to_wait_for_handle_closing_ = true;
993
994 callback_ = callback;
995 return ERR_IO_PENDING;
996 }
997
998 const HttpResponseInfo* HttpTransactionWinHttp::GetResponseInfo() const {
999 return (response_.headers || response_.ssl_info.cert) ? &response_ : NULL;
1000 }
1001
1002 LoadState HttpTransactionWinHttp::GetLoadState() const {
1003 return session_callback_->load_state();
1004 }
1005
1006 uint64 HttpTransactionWinHttp::GetUploadProgress() const {
1007 return upload_progress_;
1008 }
1009
1010 void HttpTransactionWinHttp::DoCallback(int rv) {
1011 DCHECK(rv != ERR_IO_PENDING);
1012 DCHECK(callback_);
1013
1014 // since Run may result in Read being called, clear callback_ up front.
1015 CompletionCallback* c = callback_;
1016 callback_ = NULL;
1017 c->Run(rv);
1018 }
1019
1020 bool HttpTransactionWinHttp::OpenRequest() {
1021 DCHECK(!connect_handle_);
1022 DCHECK(!request_handle_);
1023
1024 const GURL& url = request_->url;
1025 const std::string& scheme = url.scheme();
1026
1027 // Flags passed to WinHttpOpenRequest. Disable any conversion WinHttp
1028 // might perform on our URL string. We handle the escaping ourselves.
1029 DWORD open_flags = WINHTTP_FLAG_ESCAPE_DISABLE |
1030 WINHTTP_FLAG_ESCAPE_DISABLE_QUERY |
1031 WINHTTP_FLAG_NULL_CODEPAGE;
1032
1033 // We should only be dealing with HTTP at this point:
1034 DCHECK(LowerCaseEqualsASCII(scheme, "http") ||
1035 LowerCaseEqualsASCII(scheme, "https"));
1036
1037 int in_port = url.IntPort();
1038 DCHECK(in_port != url_parse::PORT_INVALID) <<
1039 "Valid URLs should have valid ports";
1040
1041 // Map to port numbers that Windows expects.
1042 INTERNET_PORT port = in_port;
1043 if (LowerCaseEqualsASCII(scheme, "https")) {
1044 is_https_ = true;
1045 open_flags |= WINHTTP_FLAG_SECURE;
1046 if (in_port == url_parse::PORT_UNSPECIFIED)
1047 port = INTERNET_DEFAULT_HTTPS_PORT;
1048 } else {
1049 if (in_port == url_parse::PORT_UNSPECIFIED)
1050 port = INTERNET_DEFAULT_HTTP_PORT;
1051 }
1052
1053 const std::string& host = url.host();
1054
1055 // Use the primary session handle unless we are talking to a TLS-intolerant
1056 // server.
1057 //
1058 // Since the SSL protocol versions enabled are an option of a session
1059 // handle, supporting TLS-intolerant servers unfortunately requires opening
1060 // an alternative session in which TLS 1.0 is disabled.
1061 if (!session_->internet() && !session_->Init(request_->user_agent)) {
1062 DLOG(ERROR) << "unable to create the internet";
1063 return false;
1064 }
1065 HINTERNET internet = session_->internet();
1066 if (is_tls_intolerant_) {
1067 if (!session_->internet_no_tls() &&
1068 !session_->InitNoTLS(request_->user_agent)) {
1069 DLOG(ERROR) << "unable to create the no-TLS alternative internet";
1070 return false;
1071 }
1072 internet = session_->internet_no_tls();
1073 }
1074
1075 // This function operates synchronously.
1076 connect_handle_ =
1077 WinHttpConnect(internet, ASCIIToWide(host).c_str(), port, 0);
1078 if (!connect_handle_) {
1079 DLOG(ERROR) << "WinHttpConnect failed: " << GetLastError();
1080 return false;
1081 }
1082
1083 std::string request_path = url.PathForRequest();
1084
1085 // This function operates synchronously.
1086 request_handle_ =
1087 WinHttpOpenRequest(connect_handle_,
1088 ASCIIToWide(request_->method).c_str(),
1089 ASCIIToWide(request_path).c_str(),
1090 NULL, // use HTTP/1.1
1091 WINHTTP_NO_REFERER, // none
1092 WINHTTP_DEFAULT_ACCEPT_TYPES, // none
1093 open_flags);
1094 if (!request_handle_) {
1095 DLOG(ERROR) << "WinHttpOpenRequest failed: " << GetLastError();
1096 return false;
1097 }
1098
1099 // TODO(darin): we may wish to prune-back the set of notifications we receive
1100 WINHTTP_STATUS_CALLBACK old_callback = WinHttpSetStatusCallback(
1101 request_handle_, StatusCallback,
1102 WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, NULL);
1103 DCHECK(old_callback == NULL);
1104 if (old_callback == WINHTTP_INVALID_STATUS_CALLBACK) {
1105 DLOG(ERROR) << "WinHttpSetStatusCallback failed:" << GetLastError();
1106 return false;
1107 }
1108
1109 DWORD_PTR ctx = reinterpret_cast<DWORD_PTR>(session_callback_.get());
1110 if (!WinHttpSetOption(request_handle_, WINHTTP_OPTION_CONTEXT_VALUE,
1111 &ctx, sizeof(ctx))) {
1112 DLOG(ERROR) << "WinHttpSetOption context value failed:" << GetLastError();
1113 return false;
1114 }
1115
1116 // We just associated a status callback context value with the request
1117 // handle.
1118 session_callback_->AddRef(); // balanced in OnHandleClosing
1119 session_->AddRefBySessionCallback();
1120
1121 // We have our own cookie and redirect management.
1122 DWORD options = WINHTTP_DISABLE_COOKIES |
1123 WINHTTP_DISABLE_REDIRECTS;
1124
1125 if (!WinHttpSetOption(request_handle_, WINHTTP_OPTION_DISABLE_FEATURE,
1126 &options, sizeof(options))) {
1127 DLOG(ERROR) << "WinHttpSetOption disable feature failed:" << GetLastError();
1128 return false;
1129 }
1130
1131 // Disable auto-login for Negotiate and NTLM auth methods.
1132 DWORD security_level = WINHTTP_AUTOLOGON_SECURITY_LEVEL_HIGH;
1133 if (!WinHttpSetOption(request_handle_, WINHTTP_OPTION_AUTOLOGON_POLICY,
1134 &security_level, sizeof(security_level))) {
1135 DLOG(ERROR) << "WinHttpSetOption autologon failed: " << GetLastError();
1136 return false;
1137 }
1138
1139 // Add request headers. WinHttp is known to convert the headers to bytes
1140 // using the system charset converter, so we use the same converter to map
1141 // our request headers to UTF-16 before handing the data to WinHttp.
1142 std::wstring request_headers = base::SysNativeMBToWide(GetRequestHeaders());
1143
1144 DWORD len = static_cast<DWORD>(request_headers.size());
1145 if (!WinHttpAddRequestHeaders(request_handle_,
1146 request_headers.c_str(),
1147 len,
1148 WINHTTP_ADDREQ_FLAG_ADD |
1149 WINHTTP_ADDREQ_FLAG_REPLACE)) {
1150 DLOG(ERROR) << "WinHttpAddRequestHeaders failed: " << GetLastError();
1151 return false;
1152 }
1153
1154 return true;
1155 }
1156
1157 int HttpTransactionWinHttp::SendRequest() {
1158 DCHECK(request_handle_);
1159
1160 // Apply any authentication (username/password) we might have.
1161 ApplyAuth();
1162
1163 // Apply any proxy info.
1164 proxy_info_.Apply(request_handle_);
1165
1166 // Check SSL server certificate revocation.
1167 if (is_https_) {
1168 bool ignore_cert_rev = (load_flags_ & LOAD_IGNORE_CERT_REVOCATION) != 0;
1169 GURL origin = request_->url.GetOrigin();
1170 const std::string& origin_spec = origin.spec();
1171 if (ignore_cert_rev)
1172 session_->IgnoreCertRev(origin_spec);
1173 else if (session_->ShouldIgnoreCertRev(origin_spec))
1174 ignore_cert_rev = true;
1175
1176 if (session_->rev_checking_enabled() && !ignore_cert_rev) {
1177 DWORD options = WINHTTP_ENABLE_SSL_REVOCATION;
1178 if (!WinHttpSetOption(request_handle_, WINHTTP_OPTION_ENABLE_FEATURE,
1179 &options, sizeof(options))) {
1180 DLOG(ERROR) << "WinHttpSetOption failed: " << GetLastError();
1181 return TranslateLastOSError();
1182 }
1183 rev_checking_enabled_ = true;
1184 }
1185 }
1186
1187 const int kCertFlags = LOAD_IGNORE_CERT_COMMON_NAME_INVALID |
1188 LOAD_IGNORE_CERT_DATE_INVALID |
1189 LOAD_IGNORE_CERT_AUTHORITY_INVALID |
1190 LOAD_IGNORE_CERT_WRONG_USAGE;
1191
1192 if (load_flags_ & kCertFlags) {
1193 DWORD security_flags;
1194 DWORD length = sizeof(security_flags);
1195
1196 if (!WinHttpQueryOption(request_handle_,
1197 WINHTTP_OPTION_SECURITY_FLAGS,
1198 &security_flags,
1199 &length)) {
1200 NOTREACHED() << "WinHttpQueryOption failed.";
1201 return TranslateLastOSError();
1202 }
1203
1204 // On Vista, WinHttpSetOption() fails with an incorrect parameter error.
1205 // WinHttpQueryOption() sets an undocumented flag (0x01000000, which seems
1206 // to be a query-only flag) in security_flags that causes this error. To
1207 // work-around it, we only keep the documented error flags.
1208 security_flags &= (SECURITY_FLAG_IGNORE_UNKNOWN_CA |
1209 SECURITY_FLAG_IGNORE_CERT_DATE_INVALID |
1210 SECURITY_FLAG_IGNORE_CERT_CN_INVALID |
1211 SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE);
1212
1213 if (load_flags_ & LOAD_IGNORE_CERT_COMMON_NAME_INVALID)
1214 security_flags |= SECURITY_FLAG_IGNORE_CERT_CN_INVALID;
1215
1216 if (load_flags_ & LOAD_IGNORE_CERT_DATE_INVALID)
1217 security_flags |= SECURITY_FLAG_IGNORE_CERT_DATE_INVALID;
1218
1219 if (load_flags_ & LOAD_IGNORE_CERT_AUTHORITY_INVALID)
1220 security_flags |= SECURITY_FLAG_IGNORE_UNKNOWN_CA;
1221
1222 if (load_flags_ & LOAD_IGNORE_CERT_WRONG_USAGE)
1223 security_flags |= SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE;
1224
1225 if (!WinHttpSetOption(request_handle_,
1226 WINHTTP_OPTION_SECURITY_FLAGS,
1227 &security_flags,
1228 sizeof(security_flags))) {
1229 NOTREACHED() << "WinHttpSetOption failed.";
1230 return TranslateLastOSError();
1231 }
1232 }
1233
1234 response_.request_time = Time::Now();
1235 response_.was_cached = false;
1236
1237 DWORD total_size = 0;
1238 if (request_->upload_data) {
1239 upload_stream_.reset(new UploadDataStream(request_->upload_data));
1240 uint64 upload_len = upload_stream_->size();
1241 if (upload_len == 0) {
1242 upload_stream_.reset();
1243 } else {
1244 // TODO(darin): no way to support >4GB uploads w/ WinHttp?
1245 if (upload_len > static_cast<uint64>(DWORD(-1))) {
1246 NOTREACHED() << "upload length is too large";
1247 return ERR_FILE_TOO_BIG;
1248 }
1249
1250 total_size = static_cast<DWORD>(upload_len);
1251 }
1252 }
1253
1254 if (request_submitted_) {
1255 request_submitted_ = false;
1256 session_->request_throttle()->NotifyRequestDone(connect_peer_);
1257 }
1258 if (proxy_info_.is_direct())
1259 connect_peer_ = request_->url.GetOrigin().spec();
1260 else
1261 connect_peer_ = proxy_info_.proxy_server();
1262 DWORD_PTR ctx = reinterpret_cast<DWORD_PTR>(session_callback_.get());
1263 if (!session_->request_throttle()->SubmitRequest(connect_peer_,
1264 request_handle_,
1265 total_size, ctx)) {
1266 last_error_ = GetLastError();
1267 DLOG(ERROR) << "WinHttpSendRequest failed: " << last_error_;
1268 return TranslateOSError(last_error_);
1269 }
1270
1271 request_submitted_ = true;
1272 return ERR_IO_PENDING;
1273 }
1274
1275 // Called after certain failures of SendRequest to reset the members opened
1276 // or modified in OpenRequest and SendRequest and call OpenRequest again.
1277 bool HttpTransactionWinHttp::ReopenRequest() {
1278 DCHECK(connect_handle_);
1279 DCHECK(request_handle_);
1280
1281 session_callback_->set_handle_closing_event(
1282 session_->handle_closing_event());
1283 WinHttpCloseHandle(request_handle_);
1284 WaitForSingleObject(session_->handle_closing_event(), INFINITE);
1285 request_handle_ = NULL;
1286 WinHttpCloseHandle(connect_handle_);
1287 connect_handle_ = NULL;
1288 session_callback_->ResetForNewRequest();
1289
1290 // Don't need to reset is_https_, rev_checking_enabled_, and
1291 // response_.request_time.
1292
1293 return OpenRequest();
1294 }
1295
1296 int HttpTransactionWinHttp::DidResolveProxy() {
1297 // We may already have a request handle if we are changing proxy config.
1298 if (!(request_handle_ ? ReopenRequest() : OpenRequest()))
1299 return TranslateLastOSError();
1300
1301 return SendRequest();
1302 }
1303
1304 int HttpTransactionWinHttp::DidReceiveError(DWORD error,
1305 DWORD secure_failure) {
1306 DCHECK(error != ERROR_SUCCESS);
1307
1308 session_callback_->set_load_state(LOAD_STATE_IDLE);
1309 need_to_wait_for_handle_closing_ = false;
1310
1311 int rv;
1312
1313 if (error == ERROR_WINHTTP_RESEND_REQUEST)
1314 return RestartInternal();
1315
1316 if (error == ERROR_WINHTTP_NAME_NOT_RESOLVED ||
1317 error == ERROR_WINHTTP_CANNOT_CONNECT ||
1318 error == ERROR_WINHTTP_TIMEOUT) {
1319 // These errors may have been caused by a proxy configuration error, or
1320 // rather they may go away by trying a different proxy config! If we have
1321 // an explicit proxy config, then we just have to report an error.
1322 if (!have_proxy_info_) {
1323 rv = session_->proxy_service()->ReconsiderProxyAfterError(
1324 request_->url, &proxy_info_, &proxy_callback_, &pac_request_);
1325 if (rv == OK) // got new proxy info to try
1326 return DidResolveProxy();
1327 if (rv == ERR_IO_PENDING) // waiting to resolve proxy info
1328 return rv;
1329 // else, fall through and just report an error.
1330 }
1331 }
1332
1333 if (error == ERROR_WINHTTP_SECURE_FAILURE) {
1334 DWORD filtered_secure_failure = FilterSecureFailure(secure_failure,
1335 load_flags_);
1336 // If load_flags_ ignores all the errors in secure_failure, we shouldn't
1337 // get the ERROR_WINHTTP_SECURE_FAILURE error.
1338 DCHECK(filtered_secure_failure || !secure_failure);
1339 error = MapSecureFailureToError(filtered_secure_failure);
1340 }
1341
1342 last_error_ = error;
1343 rv = TranslateOSError(error);
1344
1345 if ((rv == ERR_SSL_PROTOCOL_ERROR ||
1346 rv == ERR_SSL_VERSION_OR_CIPHER_MISMATCH) &&
1347 !session_callback_->request_was_probably_sent() &&
1348 session_->tls_enabled() && !is_tls_intolerant_) {
1349 // The server might be TLS intolerant. Or it might be an SSL 3.0 server
1350 // that chose a TLS-only cipher suite, which we handle in the same way.
1351 // Downgrade to SSL 3.0 and retry.
1352 is_tls_intolerant_ = true;
1353 if (!ReopenRequest())
1354 return TranslateLastOSError();
1355 return RestartInternal();
1356 }
1357 if (rv == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
1358 // TODO(wtc): Bug 1230409: We don't support SSL client authentication yet.
1359 // For now we set a null client certificate, which works on XP SP3, Vista
1360 // and later. On XP SP2 and below, this fails with ERROR_INVALID_PARAMETER
1361 // (87). This allows us to access servers that request but do not require
1362 // client certificates.
1363 if (WinHttpSetOption(request_handle_,
1364 WINHTTP_OPTION_CLIENT_CERT_CONTEXT,
1365 WINHTTP_NO_CLIENT_CERT_CONTEXT, 0))
1366 return RestartInternal();
1367 }
1368 if (IsCertificateError(rv)) {
1369 response_.ssl_info.cert = GetServerCertificate();
1370 response_.ssl_info.cert_status =
1371 MapSecureFailureToCertStatus(secure_failure);
1372 CertStatusCache* cert_status_cache = session_->cert_status_cache();
1373 cert_status_cache->SetCertStatus(*response_.ssl_info.cert,
1374 request_->url.host(),
1375 response_.ssl_info.cert_status);
1376 }
1377
1378 return rv;
1379 }
1380
1381 int HttpTransactionWinHttp::DidSendRequest() {
1382 BOOL ok;
1383 if (upload_stream_.get() && upload_stream_->buf_len() > 0) {
1384 // write upload data
1385 DWORD buf_len = static_cast<DWORD>(upload_stream_->buf_len());
1386 ok = WinHttpWriteData(request_handle_,
1387 upload_stream_->buf(),
1388 buf_len,
1389 NULL);
1390 if (ok)
1391 need_to_wait_for_handle_closing_ = true;
1392 } else {
1393 upload_stream_.reset();
1394 need_to_wait_for_handle_closing_ = false;
1395
1396 // begin receiving the response
1397 ok = WinHttpReceiveResponse(request_handle_, NULL);
1398 }
1399 return ok ? ERR_IO_PENDING : TranslateLastOSError();
1400 }
1401
1402 int HttpTransactionWinHttp::DidWriteData(DWORD num_bytes) {
1403 DCHECK(upload_stream_.get());
1404 DCHECK(num_bytes > 0);
1405
1406 upload_stream_->DidConsume(num_bytes);
1407 upload_progress_ = upload_stream_->position();
1408
1409 // OK, we are ready to start receiving the response. The code in
1410 // DidSendRequest does exactly what we want!
1411 return DidSendRequest();
1412 }
1413
1414 int HttpTransactionWinHttp::DidReadData(DWORD num_bytes) {
1415 int rv = static_cast<int>(num_bytes);
1416 DCHECK(rv >= 0);
1417
1418 session_callback_->set_load_state(LOAD_STATE_IDLE);
1419 session_callback_->reduce_bytes_available(rv);
1420 need_to_wait_for_handle_closing_ = false;
1421
1422 if (content_length_remaining_ > 0) {
1423 content_length_remaining_ -= rv;
1424
1425 // HTTP/1.0 servers are known to send more data than they report in their
1426 // Content-Length header (in the non-keepalive case). IE and Moz both
1427 // tolerate this situation, and therefore so must we.
1428 if (content_length_remaining_ < 0)
1429 content_length_remaining_ = 0;
1430 }
1431
1432 // We have read the entire response. Mark the request done to unblock a
1433 // queued request.
1434 if (rv == 0) {
1435 LogTransactionMetrics();
1436 DCHECK(request_submitted_);
1437 request_submitted_ = false;
1438 session_->request_throttle()->NotifyRequestDone(connect_peer_);
1439 }
1440
1441 return rv;
1442 }
1443
1444 void HttpTransactionWinHttp::LogTransactionMetrics() const {
1445 base::TimeDelta duration = base::Time::Now() - response_.request_time;
1446 if (60 < duration.InMinutes())
1447 return;
1448 UMA_HISTOGRAM_LONG_TIMES(L"Net.Transaction_Latency_WinHTTP", duration);
1449 }
1450
1451 int HttpTransactionWinHttp::DidReceiveHeaders() {
1452 session_callback_->set_load_state(LOAD_STATE_IDLE);
1453
1454 DWORD size = 0;
1455 if (!WinHttpQueryHeaders(request_handle_,
1456 WINHTTP_QUERY_RAW_HEADERS,
1457 WINHTTP_HEADER_NAME_BY_INDEX,
1458 NULL,
1459 &size,
1460 WINHTTP_NO_HEADER_INDEX)) {
1461 DWORD error = GetLastError();
1462 if (error != ERROR_INSUFFICIENT_BUFFER) {
1463 DLOG(ERROR) << "WinHttpQueryHeaders failed: " << GetLastError();
1464 return TranslateLastOSError();
1465 }
1466 // OK, size should tell us how much to allocate...
1467 DCHECK(size > 0);
1468 }
1469
1470 std::wstring raw_headers;
1471
1472 // 'size' is the number of bytes rather than the number of characters.
1473 DCHECK(size % 2 == 0);
1474 if (!WinHttpQueryHeaders(request_handle_,
1475 WINHTTP_QUERY_RAW_HEADERS,
1476 WINHTTP_HEADER_NAME_BY_INDEX,
1477 WriteInto(&raw_headers, size/2 + 1),
1478 &size,
1479 WINHTTP_NO_HEADER_INDEX)) {
1480 DLOG(ERROR) << "WinHttpQueryHeaders failed: " << GetLastError();
1481 return TranslateLastOSError();
1482 }
1483
1484 response_.response_time = Time::Now();
1485
1486 // From experimentation, it appears that WinHttp translates non-ASCII bytes
1487 // found in the response headers to UTF-16 assuming that they are encoded
1488 // using the default system charset. We attempt to undo that here.
1489 response_.headers =
1490 new HttpResponseHeaders(base::SysWideToNativeMB(raw_headers));
1491
1492 // WinHTTP truncates a response longer than 2GB. Perhaps it stores the
1493 // response's content length in a signed 32-bit integer. We fail rather
1494 // than reading a truncated response.
1495 if (response_.headers->GetContentLength() > 0x80000000)
1496 return ERR_FILE_TOO_BIG;
1497
1498 response_.vary_data.Init(*request_, *response_.headers);
1499 int rv = PopulateAuthChallenge();
1500 if (rv != OK)
1501 return rv;
1502
1503 // Unfortunately, WinHttp does not close the connection when a non-keepalive
1504 // response is _not_ followed by the server closing the connection. So, we
1505 // attempt to hack around this bug.
1506 if (!response_.headers->IsKeepAlive())
1507 content_length_remaining_ = response_.headers->GetContentLength();
1508
1509 return OK;
1510 }
1511
1512 // Populates response_.auth_challenge with the authentication challenge info.
1513 int HttpTransactionWinHttp::PopulateAuthChallenge() {
1514 DCHECK(response_.headers);
1515
1516 int status = response_.headers->response_code();
1517 if (status != 401 && status != 407)
1518 return OK;
1519
1520 scoped_refptr<AuthChallengeInfo> auth_info = new AuthChallengeInfo;
1521
1522 auth_info->is_proxy = (status == 407);
1523
1524 if (auth_info->is_proxy) {
1525 // TODO(wtc): get the proxy server host from proxy_info_.
1526 // TODO(wtc): internationalize?
1527 auth_info->host = L"proxy";
1528 } else {
1529 auth_info->host = ASCIIToWide(request_->url.host());
1530 }
1531
1532 // Here we're checking only the first *-Authenticate header. When a server
1533 // responds with multiple methods, we use the first.
1534 // TODO(wtc): Bug 1124614: look at all the authentication methods and pick
1535 // the best one that we support. failover to other authentication methods.
1536 std::string header_value;
1537 std::string header_name = auth_info->is_proxy ?
1538 "Proxy-Authenticate" : "WWW-Authenticate";
1539 if (!response_.headers->EnumerateHeader(NULL, header_name, &header_value))
1540 return OK;
1541
1542 // TODO(darin): Need to support RFC 2047 encoded realm strings. For now, we
1543 // limit our support to ASCII and "native code page" realm strings.
1544 std::wstring auth_header = base::SysNativeMBToWide(header_value);
1545
1546 // auth_header is a string which looks like:
1547 // Digest realm="The Awesome Site", domain="/page.html", ...
1548 std::wstring::const_iterator space = find(auth_header.begin(),
1549 auth_header.end(), L' ');
1550 auth_info->scheme.assign(auth_header.begin(), space);
1551 auth_info->realm = GetHeaderParamValue(auth_header, L"realm");
1552
1553 // Now auth_info has been fully populated. Before we swap it with
1554 // response_.auth_challenge, update the auth cache key and remove any
1555 // presumably incorrect auth data in the auth cache.
1556 std::string* auth_cache_key;
1557 AuthData* auth;
1558 if (auth_info->is_proxy) {
1559 if (!proxy_auth_)
1560 proxy_auth_ = new AuthData;
1561 auth = proxy_auth_;
1562 auth_cache_key = &proxy_auth_cache_key_;
1563 } else {
1564 if (!server_auth_)
1565 server_auth_ = new AuthData;
1566 auth = server_auth_;
1567 auth_cache_key = &server_auth_cache_key_;
1568 }
1569 *auth_cache_key = AuthCache::HttpKey(request_->url, *auth_info);
1570 DCHECK(!auth_cache_key->empty());
1571 auth->scheme = auth_info->scheme;
1572 if (auth->state == AUTH_STATE_HAVE_AUTH) {
1573 // Remove the cache entry for the credentials we just failed on.
1574 // Note: we require the username/password to match before removing
1575 // since the entry in the cache may be newer than what we used last time.
1576 AuthData* cached_auth = session_->auth_cache()->Lookup(*auth_cache_key);
1577 if (cached_auth && cached_auth->username == auth->username &&
1578 cached_auth->password == auth->password)
1579 session_->auth_cache()->Remove(*auth_cache_key);
1580 auth->state = AUTH_STATE_NEED_AUTH;
1581 }
1582 DCHECK(auth->state == AUTH_STATE_NEED_AUTH);
1583
1584 // Try to use the username/password embedded in the URL first.
1585 // (By checking !used_embedded_credentials_, we make sure that this
1586 // is only done once for the transaction.)
1587 if (!auth_info->is_proxy && request_->url.has_username() &&
1588 !used_embedded_credentials_) {
1589 // TODO(wtc) It may be necessary to unescape the username and password
1590 // after extracting them from the URL. We should be careful about
1591 // embedded nulls in that case.
1592 used_embedded_credentials_ = true;
1593 auth->state = AUTH_STATE_HAVE_AUTH;
1594 auth->username = ASCIIToWide(request_->url.username());
1595 auth->password = ASCIIToWide(request_->url.password());
1596 return RestartInternal();
1597 }
1598
1599 // Check the auth cache for an entry.
1600 AuthData* cached_auth = session_->auth_cache()->Lookup(*auth_cache_key);
1601 if (cached_auth) {
1602 auth->state = AUTH_STATE_HAVE_AUTH;
1603 auth->username = cached_auth->username;
1604 auth->password = cached_auth->password;
1605 return RestartInternal();
1606 }
1607
1608 response_.auth_challenge.swap(auth_info);
1609 return OK;
1610 }
1611
1612 static DWORD StringToAuthScheme(const std::wstring& scheme) {
1613 if (LowerCaseEqualsASCII(scheme, "basic"))
1614 return WINHTTP_AUTH_SCHEME_BASIC;
1615 if (LowerCaseEqualsASCII(scheme, "digest"))
1616 return WINHTTP_AUTH_SCHEME_DIGEST;
1617 if (LowerCaseEqualsASCII(scheme, "ntlm"))
1618 return WINHTTP_AUTH_SCHEME_NTLM;
1619 if (LowerCaseEqualsASCII(scheme, "negotiate"))
1620 return WINHTTP_AUTH_SCHEME_NEGOTIATE;
1621 if (LowerCaseEqualsASCII(scheme, "passport1.4"))
1622 return WINHTTP_AUTH_SCHEME_PASSPORT;
1623 return 0;
1624 }
1625
1626 // Applies authentication credentials to request_handle_.
1627 void HttpTransactionWinHttp::ApplyAuth() {
1628 DWORD auth_scheme;
1629 BOOL rv;
1630 if (proxy_auth_ && proxy_auth_->state == AUTH_STATE_HAVE_AUTH) {
1631 // Add auth data to cache.
1632 DCHECK(!proxy_auth_cache_key_.empty());
1633 session_->auth_cache()->Add(proxy_auth_cache_key_, proxy_auth_);
1634 auth_scheme = StringToAuthScheme(proxy_auth_->scheme);
1635 if (auth_scheme == 0)
1636 return;
1637
1638 rv = WinHttpSetCredentials(request_handle_,
1639 WINHTTP_AUTH_TARGET_PROXY,
1640 auth_scheme,
1641 proxy_auth_->username.c_str(),
1642 proxy_auth_->password.c_str(),
1643 NULL);
1644 }
1645
1646 if (server_auth_ && server_auth_->state == AUTH_STATE_HAVE_AUTH) {
1647 // Add auth data to cache.
1648 DCHECK(!server_auth_cache_key_.empty());
1649 session_->auth_cache()->Add(server_auth_cache_key_, server_auth_);
1650 auth_scheme = StringToAuthScheme(server_auth_->scheme);
1651 if (auth_scheme == 0)
1652 return;
1653
1654 rv = WinHttpSetCredentials(request_handle_,
1655 WINHTTP_AUTH_TARGET_SERVER,
1656 auth_scheme,
1657 server_auth_->username.c_str(),
1658 server_auth_->password.c_str(),
1659 NULL);
1660 }
1661 }
1662
1663 void HttpTransactionWinHttp::OnProxyInfoAvailable(int result) {
1664 if (result != OK) {
1665 DLOG(WARNING) << "failed to get proxy info: " << result;
1666 proxy_info_.UseDirect();
1667 }
1668
1669 // Balances extra reference taken when proxy resolution was initiated.
1670 session_callback_->Release();
1671
1672 pac_request_ = NULL;
1673
1674 // Since OnProxyInfoAvailable is always called asynchronously (via the
1675 // message loop), we need to trap any errors and pass them to the consumer
1676 // via their completion callback.
1677
1678 int rv = DidResolveProxy();
1679 if (rv == ERR_IO_PENDING) {
1680 session_callback_->AddRef(); // balanced when callback runs.
1681 } else {
1682 DoCallback(rv);
1683 }
1684 }
1685
1686 std::string HttpTransactionWinHttp::GetRequestHeaders() const {
1687 std::string headers;
1688
1689 if (!request_->user_agent.empty())
1690 headers += "User-Agent: " + request_->user_agent + "\r\n";
1691
1692 // Our consumer should have made sure that this is a safe referrer. See for
1693 // instance WebCore::FrameLoader::HideReferrer.
1694 if (request_->referrer.is_valid())
1695 headers += "Referer: " + request_->referrer.spec() + "\r\n";
1696
1697 // IE and Safari do this. Presumably it is to support sending a HEAD request
1698 // to an URL that only expects to be sent a POST or some other method that
1699 // normally would have a message body.
1700 if (request_->method == "HEAD")
1701 headers += "Content-Length: 0\r\n";
1702
1703 // Honor load flags that impact proxy caches.
1704 if (request_->load_flags & LOAD_BYPASS_CACHE) {
1705 headers += "Pragma: no-cache\r\nCache-Control: no-cache\r\n";
1706 } else if (request_->load_flags & LOAD_VALIDATE_CACHE) {
1707 headers += "Cache-Control: max-age=0\r\n";
1708 }
1709
1710 // TODO(darin): Prune out duplicate headers?
1711 headers += request_->extra_headers;
1712
1713 return headers;
1714 }
1715
1716 // Retrieves the SSL server certificate associated with the transaction.
1717 // The caller is responsible for freeing the certificate.
1718 X509Certificate* HttpTransactionWinHttp::GetServerCertificate() const {
1719 DCHECK(is_https_);
1720 PCCERT_CONTEXT cert_context = NULL;
1721 DWORD length = sizeof(cert_context);
1722 if (!WinHttpQueryOption(request_handle_,
1723 WINHTTP_OPTION_SERVER_CERT_CONTEXT,
1724 &cert_context,
1725 &length)) {
1726 return NULL;
1727 }
1728 // cert_context may be NULL here even though WinHttpQueryOption succeeded.
1729 // For example, a proxy server may return a 404 error page to report the
1730 // DNS resolution failure of the server's hostname.
1731 if (!cert_context)
1732 return NULL;
1733 return X509Certificate::CreateFromHandle(cert_context);
1734 }
1735
1736 // Retrieves the security strength, in bits, of the SSL cipher suite
1737 // associated with the transaction.
1738 int HttpTransactionWinHttp::GetSecurityBits() const {
1739 DCHECK(is_https_);
1740 DWORD key_bits = 0;
1741 DWORD length = sizeof(key_bits);
1742 if (!WinHttpQueryOption(request_handle_,
1743 WINHTTP_OPTION_SECURITY_KEY_BITNESS,
1744 &key_bits,
1745 &length)) {
1746 return -1;
1747 }
1748 return key_bits;
1749 }
1750
1751 void HttpTransactionWinHttp::PopulateSSLInfo(DWORD secure_failure) {
1752 if (is_https_) {
1753 response_.ssl_info.cert = GetServerCertificate();
1754 response_.ssl_info.security_bits = GetSecurityBits();
1755 // If there is no cert (such as when the proxy server makes up a
1756 // 404 response to report a server name resolution error), don't set
1757 // the cert status.
1758 if (!response_.ssl_info.cert)
1759 return;
1760 response_.ssl_info.cert_status =
1761 MapSecureFailureToCertStatus(secure_failure);
1762 // WinHTTP does not always return a cert status once we ignored errors
1763 // for a cert. (Our experiments showed that WinHTTP reliably returns a
1764 // cert status only when there are unignored errors or when we resend a
1765 // request with the errors ignored.) So we have to remember what the
1766 // last status was for a cert. Note that if the cert status changes
1767 // from error to OK, we won't know that. If we have never stored our
1768 // status in the CertStatusCache (meaning no errors so far), then it is
1769 // OK (0).
1770 CertStatusCache* cert_status_cache = session_->cert_status_cache();
1771 if (net::IsCertStatusError(response_.ssl_info.cert_status)) {
1772 cert_status_cache->SetCertStatus(*response_.ssl_info.cert,
1773 request_->url.host(),
1774 response_.ssl_info.cert_status);
1775 } else {
1776 response_.ssl_info.cert_status |=
1777 cert_status_cache->GetCertStatus(*response_.ssl_info.cert,
1778 request_->url.host()) &
1779 net::CERT_STATUS_ALL_ERRORS;
1780 }
1781
1782 if (rev_checking_enabled_)
1783 response_.ssl_info.cert_status |= CERT_STATUS_REV_CHECKING_ENABLED;
1784 } else {
1785 // If this is not https, we should not get a cert status.
1786 DCHECK(!secure_failure);
1787 }
1788 }
1789
1790 void HttpTransactionWinHttp::HandleStatusCallback(DWORD status,
1791 DWORD_PTR result,
1792 DWORD error,
1793 DWORD secure_failure) {
1794 int rv;
1795
1796 switch (status) {
1797 case WINHTTP_CALLBACK_STATUS_REQUEST_ERROR:
1798 rv = DidReceiveError(error, secure_failure);
1799 break;
1800 case WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE:
1801 PopulateSSLInfo(secure_failure);
1802 rv = DidSendRequest();
1803 break;
1804 case WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE:
1805 rv = DidWriteData(static_cast<DWORD>(result));
1806 break;
1807 case WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE:
1808 rv = DidReceiveHeaders();
1809 break;
1810 case WINHTTP_CALLBACK_STATUS_READ_COMPLETE:
1811 rv = DidReadData(static_cast<DWORD>(result));
1812 break;
1813 default:
1814 NOTREACHED() << "unexpected status code";
1815 rv = ERR_UNEXPECTED;
1816 break;
1817 }
1818
1819 if (rv == ERR_IO_PENDING) {
1820 session_callback_->AddRef(); // balanced when callback runs.
1821 } else if (callback_) {
1822 DoCallback(rv);
1823 }
1824 }
1825
1826 } // namespace net
1827
OLDNEW
« no previous file with comments | « net/http/http_transaction_winhttp.h ('k') | net/http/http_transaction_winhttp_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698