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

Side by Side Diff: chrome_frame/urlmon_url_request.cc

Issue 545093: Refactor host network (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 10 years, 10 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 | « chrome_frame/urlmon_url_request.h ('k') | chrome_frame/urlmon_url_request_private.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2009 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 "chrome_frame/urlmon_url_request.h" 5 #include "chrome_frame/urlmon_url_request.h"
6 6
7 #include <wininet.h> 7 #include <wininet.h>
8 #include <urlmon.h> 8 #include <urlmon.h>
9 9
10 #include "base/scoped_ptr.h" 10 #include "base/scoped_ptr.h"
11 #include "base/string_util.h" 11 #include "base/string_util.h"
12 #include "base/logging.h" 12 #include "base/logging.h"
13 #include "base/message_loop.h" 13 #include "base/message_loop.h"
14 #include "chrome_frame/chrome_frame_activex_base.h"
15 #include "chrome_frame/extra_system_apis.h" 14 #include "chrome_frame/extra_system_apis.h"
16 #include "chrome_frame/html_utils.h" 15 #include "chrome_frame/html_utils.h"
16 #include "chrome_frame/urlmon_url_request_private.h"
17 #include "chrome_frame/urlmon_upload_data_stream.h" 17 #include "chrome_frame/urlmon_upload_data_stream.h"
18 #include "chrome_frame/utils.h" 18 #include "chrome_frame/utils.h"
19 #include "net/http/http_util.h" 19 #include "net/http/http_util.h"
20 #include "net/http/http_response_headers.h" 20 #include "net/http/http_response_headers.h"
21 21
22 static const LARGE_INTEGER kZero = {0}; 22 static const LARGE_INTEGER kZero = {0};
23 static const ULARGE_INTEGER kUnsignedZero = {0}; 23 static const ULARGE_INTEGER kUnsignedZero = {0};
24 int UrlmonUrlRequest::instance_count_ = 0;
25 24
26 // This class wraps the IBindCtx interface which is passed in when our active 25 // This class wraps the IBindCtx interface which is passed in when our active
27 // document object is instantiated. The IBindCtx interface is created on 26 // document object is instantiated. The IBindCtx interface is created on
28 // the UI thread and hence cannot be used as is on the worker thread which 27 // the UI thread and hence cannot be used as is on the worker thread which
29 // handles URL requests. We unmarshal the IBindCtx interface and invoke 28 // handles URL requests. We unmarshal the IBindCtx interface and invoke
30 // the corresponding method on the unmarshaled object. The object implementing 29 // the corresponding method on the unmarshaled object. The object implementing
31 // the IBindCtx interface also implements IMarshal. However it seems to have a 30 // the IBindCtx interface also implements IMarshal. However it seems to have a
32 // bug where in subsequent download requests for the same URL fail. We work 31 // bug where in subsequent download requests for the same URL fail. We work
33 // around this issue by using the standard marshaler instead. 32 // around this issue by using the standard marshaler instead.
34 class WrappedBindContext : public IBindCtx, 33 class WrappedBindContext : public IBindCtx,
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after
215 DCHECK(marshalled_bind_context_.get() != NULL); 214 DCHECK(marshalled_bind_context_.get() != NULL);
216 } 215 }
217 return marshalled_bind_context_.QueryInterface(bind_context); 216 return marshalled_bind_context_.QueryInterface(bind_context);
218 } 217 }
219 218
220 ScopedComPtr<IStream> marshaled_stream_; 219 ScopedComPtr<IStream> marshaled_stream_;
221 ScopedComPtr<IBindCtx> marshalled_bind_context_; 220 ScopedComPtr<IBindCtx> marshalled_bind_context_;
222 ScopedComPtr<IMarshal> standard_marshal_; 221 ScopedComPtr<IMarshal> standard_marshal_;
223 }; 222 };
224 223
224 STDMETHODIMP UrlmonUrlRequest::SendStream::Write(const void * buffer,
225 ULONG size,
226 ULONG* size_written) {
227 DCHECK(request_);
228 int size_to_write = static_cast<int>(
229 std::min(static_cast<ULONG>(MAXINT), size));
230 request_->delegate_->OnReadComplete(request_->id(), buffer,
231 size_to_write);
232 if (size_written)
233 *size_written = size_to_write;
234 return S_OK;
235 }
236
237 int UrlmonUrlRequest::instance_count_ = 0;
238
225 UrlmonUrlRequest::UrlmonUrlRequest() 239 UrlmonUrlRequest::UrlmonUrlRequest()
226 : pending_read_size_(0), 240 : pending_read_size_(0),
227 status_(URLRequestStatus::FAILED, net::ERR_FAILED), 241 thread_(NULL),
228 thread_(PlatformThread::CurrentId()), 242 parent_window_(NULL) {
229 redirect_status_(0),
230 parent_window_(NULL),
231 worker_thread_(NULL),
232 ignore_redirect_stop_binding_error_(false) {
233 DLOG(INFO) << StringPrintf("Created request. Obj: %X", this) 243 DLOG(INFO) << StringPrintf("Created request. Obj: %X", this)
234 << " Count: " << ++instance_count_; 244 << " Count: " << ++instance_count_;
235 } 245 }
236 246
237 UrlmonUrlRequest::~UrlmonUrlRequest() { 247 UrlmonUrlRequest::~UrlmonUrlRequest() {
238 DLOG(INFO) << StringPrintf("Deleted request. Obj: %X", this) 248 DLOG(INFO) << StringPrintf("Deleted request. Obj: %X", this)
239 << " Count: " << --instance_count_; 249 << " Count: " << --instance_count_;
240 } 250 }
241 251
242 bool UrlmonUrlRequest::Start() { 252 bool UrlmonUrlRequest::Start() {
243 DCHECK_EQ(PlatformThread::CurrentId(), thread_); 253 thread_ = PlatformThread::CurrentId();
244 254 status_.Start();
245 if (!worker_thread_ || !worker_thread_->message_loop()) { 255 HRESULT hr = StartAsyncDownload();
246 NOTREACHED() << __FUNCTION__ << " Urlmon request thread not initialized"; 256 if (FAILED(hr)) {
247 return false; 257 status_.set_result(URLRequestStatus::FAILED, HresultToNetError(hr));
258 NotifyDelegateAndDie();
248 } 259 }
249
250 Create(HWND_MESSAGE);
251 if (!IsWindow()) {
252 NOTREACHED() << "Failed to create urlmon message window: "
253 << GetLastError();
254 return false;
255 }
256
257 // Take a self reference to maintain COM lifetime. This will be released
258 // in OnFinalMessage
259 AddRef();
260 request_handler()->AddRequest(this);
261
262 worker_thread_->message_loop()->PostTask(
263 FROM_HERE, NewRunnableMethod(this, &UrlmonUrlRequest::StartAsync));
264
265 return true; 260 return true;
266 } 261 }
267 262
268 void UrlmonUrlRequest::Stop() { 263 void UrlmonUrlRequest::Stop() {
269 DCHECK_EQ(PlatformThread::CurrentId(), thread_); 264 DCHECK_EQ(thread_, PlatformThread::CurrentId());
265 DCHECK((status_.get_state() != Status::DONE) == (binding_ != NULL));
266 Status::State state = status_.get_state();
267 switch (state) {
268 case Status::WORKING:
269 status_.Cancel();
270 binding_->Abort();
271 break;
270 272
271 if (!worker_thread_ || !worker_thread_->message_loop()) { 273 case Status::ABORTING:
272 NOTREACHED() << __FUNCTION__ << " Urlmon request thread not initialized"; 274 status_.Cancel();
273 return; 275 break;
274 }
275 276
276 // We can remove the request from the map safely here if it is still valid. 277 case Status::DONE:
277 // There is an additional reference on the UrlmonUrlRequest instance which 278 status_.Cancel();
278 // is released when the task scheduled by the EndRequest function executes. 279 NotifyDelegateAndDie();
279 request_handler()->RemoveRequest(this); 280 break;
280
281 worker_thread_->message_loop()->PostTask(
282 FROM_HERE, NewRunnableMethod(this, &UrlmonUrlRequest::StopAsync));
283 }
284
285 void UrlmonUrlRequest::StartAsync() {
286 DCHECK(worker_thread_ != NULL);
287
288 status_.set_status(URLRequestStatus::IO_PENDING);
289 HRESULT hr = StartAsyncDownload();
290 if (FAILED(hr)) {
291 // Do not call EndRequest() here since it will attempt to free references
292 // that have not been established.
293 status_.set_os_error(HresultToNetError(hr));
294 status_.set_status(URLRequestStatus::FAILED);
295 DLOG(ERROR) << "StartAsyncDownload failed";
296 EndRequest();
297 return;
298 } 281 }
299 } 282 }
300 283
301 void UrlmonUrlRequest::StopAsync() { 284 bool UrlmonUrlRequest::Read(int bytes_to_read) {
302 DCHECK(worker_thread_ != NULL); 285 DCHECK_EQ(thread_, PlatformThread::CurrentId());
286 // Re-entrancy check. Thou shall not call Read() while processOnReadComplete!!
287 DCHECK_EQ(0, pending_read_size_);
288 if (pending_read_size_ != 0)
289 return false;
303 290
304 if (binding_) { 291 DCHECK((status_.get_state() != Status::DONE) == (binding_ != NULL));
305 binding_->Abort(); 292 if (status_.get_state() == Status::ABORTING) {
306 } else { 293 return true;
307 status_.set_status(URLRequestStatus::CANCELED);
308 status_.set_os_error(net::ERR_FAILED);
309 EndRequest();
310 }
311 }
312
313 void UrlmonUrlRequest::OnFinalMessage(HWND window) {
314 m_hWnd = NULL;
315 // Release the outstanding reference in the context of the UI thread to
316 // ensure that our instance gets deleted in the same thread which created it.
317 Release();
318 }
319
320 bool UrlmonUrlRequest::Read(int bytes_to_read) {
321 DCHECK_EQ(PlatformThread::CurrentId(), thread_);
322
323 DLOG(INFO) << StringPrintf("URL: %s Obj: %X", url().c_str(), this);
324
325 if (!worker_thread_ || !worker_thread_->message_loop()) {
326 NOTREACHED() << __FUNCTION__ << " Urlmon request thread not initialized";
327 return false;
328 } 294 }
329 295
330 worker_thread_->message_loop()->PostTask(
331 FROM_HERE, NewRunnableMethod(this, &UrlmonUrlRequest::ReadAsync,
332 bytes_to_read));
333 return true;
334 }
335
336 void UrlmonUrlRequest::TransferToHost(IUnknown* host) {
337 DCHECK_EQ(PlatformThread::CurrentId(), thread_);
338 DCHECK(host);
339 DCHECK(moniker_);
340 if (moniker_) {
341 ScopedComPtr<IBindCtx> bind_context;
342 CreateBindCtx(0, bind_context.Receive());
343 DCHECK(bind_context);
344 NavigateBrowserToMoniker(host, moniker_, NULL, bind_context, NULL);
345 moniker_.Release();
346 }
347 }
348
349 void UrlmonUrlRequest::ReadAsync(int bytes_to_read) {
350 // Send cached data if available. 296 // Send cached data if available.
351 CComObjectStackEx<SendStream> send_stream; 297 CComObjectStackEx<SendStream> send_stream;
352 send_stream.Initialize(this); 298 send_stream.Initialize(this);
353 299
354 size_t bytes_copied = 0; 300 size_t bytes_copied = 0;
355 if (cached_data_.is_valid() && cached_data_.Read(&send_stream, bytes_to_read, 301 if (delegate_ && cached_data_.is_valid() &&
356 &bytes_copied)) { 302 cached_data_.Read(&send_stream, bytes_to_read, &bytes_copied)) {
357 DLOG(INFO) << StringPrintf("URL: %s Obj: %X - bytes read from cache: %d", 303 DLOG(INFO) << StringPrintf("URL: %s Obj: %X - bytes read from cache: %d",
358 url().c_str(), this, bytes_copied); 304 url().c_str(), this, bytes_copied);
359 return; 305 return true;
360 } 306 }
361 307
362 // if the request is finished or there's nothing more to read 308 if (status_.get_state() == Status::WORKING) {
363 // then end the request 309 DLOG(INFO) << StringPrintf("URL: %s Obj: %X", url().c_str(), this) <<
364 if (!status_.is_io_pending() || !binding_) { 310 "- Read pending for: " << bytes_to_read;
365 DLOG(INFO) << StringPrintf("URL: %s Obj: %X. Response finished. Status: %d", 311 pending_read_size_ = bytes_to_read;
366 url().c_str(), this, status_.status()); 312 } else {
367 EndRequest(); 313 DLOG(INFO) << StringPrintf("URL: %s Obj: %X. Response finished.",
368 return; 314 url().c_str(), this);
315 NotifyDelegateAndDie();
369 } 316 }
370 317
371 pending_read_size_ = bytes_to_read; 318 return true;
372 DLOG(INFO) << StringPrintf("URL: %s Obj: %X", url().c_str(), this) <<
373 "- Read pending for: " << bytes_to_read;
374 } 319 }
375 320
376 STDMETHODIMP UrlmonUrlRequest::OnStartBinding( 321 HRESULT UrlmonUrlRequest::ConnectToExistingMoniker(IMoniker* moniker,
377 DWORD reserved, IBinding *binding) { 322 IBindCtx* context,
323 const std::wstring& url) {
324 if (!moniker || url.empty()) {
325 NOTREACHED() << "Invalid arguments";
326 return E_INVALIDARG;
327 }
328
329 DCHECK(moniker_.get() == NULL);
330 DCHECK(bind_context_.get() == NULL);
331
332 bind_context_ = context;
333 moniker_ = moniker;
334 set_url(WideToUTF8(url));
335 return S_OK;
336 }
337
338 void UrlmonUrlRequest::StealMoniker(IMoniker** moniker) {
339 // Could be called in any thread. There should be no race
340 // since moniker_ is not released while we are in manager's request map.
341 *moniker = moniker_.Detach();
342 }
343
344 STDMETHODIMP UrlmonUrlRequest::OnStartBinding(DWORD reserved,
345 IBinding *binding) {
346 DCHECK_EQ(thread_, PlatformThread::CurrentId());
378 binding_ = binding; 347 binding_ = binding;
379 return S_OK; 348 return S_OK;
380 } 349 }
381 350
382 STDMETHODIMP UrlmonUrlRequest::GetPriority(LONG *priority) { 351 STDMETHODIMP UrlmonUrlRequest::GetPriority(LONG *priority) {
383 if (!priority) 352 if (!priority)
384 return E_POINTER; 353 return E_POINTER;
385 *priority = THREAD_PRIORITY_NORMAL; 354 *priority = THREAD_PRIORITY_NORMAL;
386 return S_OK; 355 return S_OK;
387 } 356 }
388 357
389 STDMETHODIMP UrlmonUrlRequest::OnLowResource(DWORD reserved) { 358 STDMETHODIMP UrlmonUrlRequest::OnLowResource(DWORD reserved) {
390 return S_OK; 359 return S_OK;
391 } 360 }
392 361
393 STDMETHODIMP UrlmonUrlRequest::OnProgress(ULONG progress, ULONG max_progress, 362 STDMETHODIMP UrlmonUrlRequest::OnProgress(ULONG progress, ULONG max_progress,
394 ULONG status_code, LPCWSTR status_text) { 363 ULONG status_code, LPCWSTR status_text) {
395 static const int kDefaultHttpRedirectCode = 302; 364 DCHECK_EQ(thread_, PlatformThread::CurrentId());
396
397 switch (status_code) { 365 switch (status_code) {
398 case BINDSTATUS_REDIRECTING: { 366 case BINDSTATUS_REDIRECTING: {
367 DLOG(INFO) << "URL: " << url() << " redirected to " << status_text;
399 // Fetch the redirect status as they aren't all equal (307 in particular 368 // Fetch the redirect status as they aren't all equal (307 in particular
400 // retains the HTTP request verb). 369 // retains the HTTP request verb).
401 // We assume that valid redirect codes are 301, 302, 303 and 307. If we 370 int http_code = GetHttpResponseStatus();
402 // receive anything else we would abort the request which would 371 status_.SetRedirected(http_code, WideToUTF8(status_text));
403 // eventually result in the request getting cancelled in Chrome. 372 // Abort. We will inform Chrome in OnStopBinding callback.
404 int redirect_status = GetHttpResponseStatus(); 373 binding_->Abort();
405 DCHECK(status_text != NULL);
406 DLOG(INFO) << "URL: " << url() << " redirected to "
407 << status_text;
408 redirect_url_ = status_text;
409 // At times we receive invalid redirect codes like 0, 200, etc. We
410 // default to 302 in this case.
411 if (!net::HttpResponseHeaders::IsRedirectResponseCode(redirect_status))
412 redirect_status = kDefaultHttpRedirectCode;
413 redirect_status_ = redirect_status;
414 // Chrome should decide whether a redirect has to be followed. To achieve
415 // this we send over a fake response to Chrome and abort the redirect.
416 std::string headers = GetHttpHeaders();
417 OnResponse(0, UTF8ToWide(headers).c_str(), NULL, NULL);
418 ignore_redirect_stop_binding_error_ = true;
419 DCHECK(binding_ != NULL);
420 if (binding_) {
421 binding_->Abort();
422 binding_ = NULL;
423 }
424 return E_ABORT; 374 return E_ABORT;
425 } 375 }
426 376
427 default: 377 default:
428 DLOG(INFO) << " Obj: " << std::hex << this << " OnProgress(" << url() 378 DLOG(INFO) << " Obj: " << std::hex << this << " OnProgress(" << url()
429 << StringPrintf(L") code: %i status: %ls", status_code, status_text); 379 << StringPrintf(L") code: %i status: %ls", status_code, status_text);
430 break; 380 break;
431 } 381 }
432 382
433 return S_OK; 383 return S_OK;
434 } 384 }
435 385
436 STDMETHODIMP UrlmonUrlRequest::OnStopBinding(HRESULT result, LPCWSTR error) { 386 STDMETHODIMP UrlmonUrlRequest::OnStopBinding(HRESULT result, LPCWSTR error) {
437 DCHECK(worker_thread_ != NULL); 387 DCHECK_EQ(thread_, PlatformThread::CurrentId());
438 DCHECK_EQ(PlatformThread::CurrentId(), worker_thread_->thread_id()); 388 DLOG(INFO) << StringPrintf("URL: %s Obj: %X", url().c_str(), this) <<
389 " - Request stopped, Result: " << std::hex << result;
390 DCHECK(status_.get_state() == Status::WORKING ||
391 status_.get_state() == Status::ABORTING);
392 Status::State state = status_.get_state();
439 393
440 DLOG(INFO) << StringPrintf("URL: %s Obj: %X", url().c_str(), this) << 394 // Mark we a are done.
441 " - Request stopped, Result: " << std::hex << result << 395 status_.Done();
442 " Status: " << status_.status();
443 396
444 if (FAILED(result)) { 397 if (state == Status::WORKING) {
445 status_.set_status(URLRequestStatus::FAILED); 398 status_.set_result(result);
446 status_.set_os_error(HresultToNetError(result)); 399
447 EndRequest(); 400 // The code below seems easy but it is not. :)
448 } else { 401 // we cannot have pending read and data_avail at the same time.
449 status_.set_status(URLRequestStatus::SUCCESS); 402 DCHECK(!(pending_read_size_ > 0 && cached_data_.is_valid()));
450 status_.set_os_error(0); 403
451 ReleaseBindings(); 404 // We have some data, but Chrome has not yet read it. Wait until Chrome
452 // In most cases we receive the end request notification from Chrome. 405 // read the remaining of the data and then send the error/success code.
453 // However at times requests can complete without us receiving any 406 if (cached_data_.is_valid()) {
454 // data. In this case we need to inform Chrome that this request has been 407 ReleaseBindings();
455 // completed to prevent Chrome from waiting forever for data for this 408 return S_OK;
456 // request.
457 if (pending_read_size_) {
458 pending_read_size_ = 0;
459 OnResponseEnd(status_);
460 } 409 }
410
411 NotifyDelegateAndDie();
412 return S_OK;
461 } 413 }
462 414
415 // Status::ABORTING
416 if (status_.was_redirected()) {
417 // Just release bindings here. Chrome will issue EndRequest(request_id)
418 // after processing headers we had provided.
419 std::string headers = GetHttpHeaders();
420 OnResponse(0, UTF8ToWide(headers).c_str(), NULL, NULL);
421 ReleaseBindings();
422 return S_OK;
423 }
424
425 // Stop invoked.
426 NotifyDelegateAndDie();
463 return S_OK; 427 return S_OK;
464 } 428 }
465 429
466 STDMETHODIMP UrlmonUrlRequest::GetBindInfo(DWORD* bind_flags, 430 STDMETHODIMP UrlmonUrlRequest::GetBindInfo(DWORD* bind_flags,
467 BINDINFO *bind_info) { 431 BINDINFO *bind_info) {
468 DCHECK(worker_thread_ != NULL);
469 DCHECK_EQ(PlatformThread::CurrentId(), worker_thread_->thread_id());
470 432
471 if ((bind_info == NULL) || (bind_info->cbSize == 0) || (bind_flags == NULL)) 433 if ((bind_info == NULL) || (bind_info->cbSize == 0) || (bind_flags == NULL))
472 return E_INVALIDARG; 434 return E_INVALIDARG;
473 435
474 *bind_flags = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA; 436 *bind_flags = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA;
475 437
476 bool upload_data = false; 438 bool upload_data = false;
477 439
478 if (LowerCaseEqualsASCII(method(), "get")) { 440 if (LowerCaseEqualsASCII(method(), "get")) {
479 bind_info->dwBindVerb = BINDVERB_GET; 441 bind_info->dwBindVerb = BINDVERB_GET;
480 } else if (LowerCaseEqualsASCII(method(), "post")) { 442 } else if (LowerCaseEqualsASCII(method(), "post")) {
481 bind_info->dwBindVerb = BINDVERB_POST; 443 bind_info->dwBindVerb = BINDVERB_POST;
482 upload_data = true; 444 upload_data = true;
483 } else if (LowerCaseEqualsASCII(method(), "put")) { 445 } else if (LowerCaseEqualsASCII(method(), "put")) {
484 bind_info->dwBindVerb = BINDVERB_PUT; 446 bind_info->dwBindVerb = BINDVERB_PUT;
485 upload_data = true; 447 upload_data = true;
486 } else { 448 } else {
487 NOTREACHED() << "Unknown HTTP method."; 449 NOTREACHED() << "Unknown HTTP method.";
488 status_.set_status(URLRequestStatus::FAILED); 450 status_.set_result(URLRequestStatus::FAILED, net::ERR_METHOD_NOT_SUPPORTED);
489 status_.set_os_error(net::ERR_METHOD_NOT_SUPPORTED); 451 NotifyDelegateAndDie();
490 EndRequest();
491 return E_FAIL; 452 return E_FAIL;
492 } 453 }
493 454
494 if (upload_data) { 455 if (upload_data) {
495 // Bypass caching proxies on POSTs and PUTs and avoid writing responses to 456 // Bypass caching proxies on POSTs and PUTs and avoid writing responses to
496 // these requests to the browser's cache 457 // these requests to the browser's cache
497 *bind_flags |= BINDF_GETNEWESTVERSION | BINDF_NOWRITECACHE | 458 *bind_flags |= BINDF_GETNEWESTVERSION | BINDF_NOWRITECACHE |
498 BINDF_PRAGMA_NO_CACHE; 459 BINDF_PRAGMA_NO_CACHE;
499 460
500 // Initialize the STGMEDIUM. 461 // Initialize the STGMEDIUM.
(...skipping 11 matching lines...) Expand all
512 << "POST request with no data!"; 473 << "POST request with no data!";
513 } 474 }
514 } 475 }
515 476
516 return S_OK; 477 return S_OK;
517 } 478 }
518 479
519 STDMETHODIMP UrlmonUrlRequest::OnDataAvailable(DWORD flags, DWORD size, 480 STDMETHODIMP UrlmonUrlRequest::OnDataAvailable(DWORD flags, DWORD size,
520 FORMATETC* formatetc, 481 FORMATETC* formatetc,
521 STGMEDIUM* storage) { 482 STGMEDIUM* storage) {
522 DCHECK(worker_thread_ != NULL);
523 DCHECK_EQ(PlatformThread::CurrentId(), worker_thread_->thread_id());
524
525 DLOG(INFO) << StringPrintf("URL: %s Obj: %X - Bytes available: %d", 483 DLOG(INFO) << StringPrintf("URL: %s Obj: %X - Bytes available: %d",
526 url().c_str(), this, size); 484 url().c_str(), this, size);
527 485
528 if (!storage || (storage->tymed != TYMED_ISTREAM)) { 486 if (!storage || (storage->tymed != TYMED_ISTREAM)) {
529 NOTREACHED(); 487 NOTREACHED();
530 return E_INVALIDARG; 488 return E_INVALIDARG;
531 } 489 }
532 490
533 IStream* read_stream = storage->pstm; 491 IStream* read_stream = storage->pstm;
534 if (!read_stream) { 492 if (!read_stream) {
(...skipping 21 matching lines...) Expand all
556 cached_data_.Read(&send_stream, pending_read_size_, &pending_read_size_); 514 cached_data_.Read(&send_stream, pending_read_size_, &pending_read_size_);
557 DLOG(INFO) << StringPrintf("URL: %s Obj: %X", url().c_str(), this) << 515 DLOG(INFO) << StringPrintf("URL: %s Obj: %X", url().c_str(), this) <<
558 " - size read: " << pending_read_size_; 516 " - size read: " << pending_read_size_;
559 pending_read_size_ = 0; 517 pending_read_size_ = 0;
560 } else { 518 } else {
561 DLOG(INFO) << StringPrintf("URL: %s Obj: %X", url().c_str(), this) << 519 DLOG(INFO) << StringPrintf("URL: %s Obj: %X", url().c_str(), this) <<
562 " - waiting for remote read"; 520 " - waiting for remote read";
563 } 521 }
564 522
565 if (BSCF_LASTDATANOTIFICATION & flags) { 523 if (BSCF_LASTDATANOTIFICATION & flags) {
566 status_.set_status(URLRequestStatus::SUCCESS);
567 DLOG(INFO) << StringPrintf("URL: %s Obj: %X", url().c_str(), this) << 524 DLOG(INFO) << StringPrintf("URL: %s Obj: %X", url().c_str(), this) <<
568 " - end of data."; 525 " - end of data.";
569 } 526 }
570 527
571 return S_OK; 528 return S_OK;
572 } 529 }
573 530
574 STDMETHODIMP UrlmonUrlRequest::OnObjectAvailable(REFIID iid, IUnknown* object) { 531 STDMETHODIMP UrlmonUrlRequest::OnObjectAvailable(REFIID iid, IUnknown* object) {
575 // We are calling BindToStorage on the moniker we should always get called 532 // We are calling BindToStorage on the moniker we should always get called
576 // back on OnDataAvailable and should never get OnObjectAvailable 533 // back on OnDataAvailable and should never get OnObjectAvailable
577 NOTREACHED(); 534 NOTREACHED();
578 return E_NOTIMPL; 535 return E_NOTIMPL;
579 } 536 }
580 537
581 STDMETHODIMP UrlmonUrlRequest::BeginningTransaction(const wchar_t* url, 538 STDMETHODIMP UrlmonUrlRequest::BeginningTransaction(const wchar_t* url,
582 const wchar_t* current_headers, DWORD reserved, 539 const wchar_t* current_headers, DWORD reserved,
583 wchar_t** additional_headers) { 540 wchar_t** additional_headers) {
584 DCHECK(worker_thread_ != NULL); 541 DCHECK_EQ(thread_, PlatformThread::CurrentId());
585 DCHECK_EQ(PlatformThread::CurrentId(), worker_thread_->thread_id());
586
587 if (!additional_headers) { 542 if (!additional_headers) {
588 NOTREACHED(); 543 NOTREACHED();
589 return E_POINTER; 544 return E_POINTER;
590 } 545 }
591 546
592 DLOG(INFO) << "URL: " << url << " Obj: " << std::hex << this << 547 DLOG(INFO) << "URL: " << url << " Obj: " << std::hex << this <<
593 " - Request headers: \n" << current_headers; 548 " - Request headers: \n" << current_headers;
594 549
595 if (!binding_) { 550 if (status_.get_state() == Status::ABORTING) {
596 // At times the BINDSTATUS_REDIRECTING notification which is sent to the 551 // At times the BINDSTATUS_REDIRECTING notification which is sent to the
597 // IBindStatusCallback interface does not have an accompanying HTTP 552 // IBindStatusCallback interface does not have an accompanying HTTP
598 // redirect status code, i.e. the attempt to query the HTTP status code 553 // redirect status code, i.e. the attempt to query the HTTP status code
599 // from the binding returns 0, 200, etc which are invalid redirect codes. 554 // from the binding returns 0, 200, etc which are invalid redirect codes.
600 // We don't want urlmon to follow redirects. We return E_ABORT in our 555 // We don't want urlmon to follow redirects. We return E_ABORT in our
601 // IBindStatusCallback::OnProgress function and also abort the binding. 556 // IBindStatusCallback::OnProgress function and also abort the binding.
602 // However urlmon still tries to establish a transaction with the 557 // However urlmon still tries to establish a transaction with the
603 // redirected URL which confuses the web server. 558 // redirected URL which confuses the web server.
604 // Fix is to abort the attempted transaction. 559 // Fix is to abort the attempted transaction.
605 DCHECK(ignore_redirect_stop_binding_error_);
606 DLOG(WARNING) << __FUNCTION__ 560 DLOG(WARNING) << __FUNCTION__
607 << ": Aborting connection to URL:" 561 << ": Aborting connection to URL:"
608 << url 562 << url
609 << " as the binding has been aborted"; 563 << " as the binding has been aborted";
610 return E_ABORT; 564 return E_ABORT;
611 } 565 }
612 566
613 HRESULT hr = S_OK; 567 HRESULT hr = S_OK;
614 568
615 std::string new_headers; 569 std::string new_headers;
(...skipping 26 matching lines...) Expand all
642 new_headers.size()); 596 new_headers.size());
643 } 597 }
644 } 598 }
645 599
646 return hr; 600 return hr;
647 } 601 }
648 602
649 STDMETHODIMP UrlmonUrlRequest::OnResponse(DWORD dwResponseCode, 603 STDMETHODIMP UrlmonUrlRequest::OnResponse(DWORD dwResponseCode,
650 const wchar_t* response_headers, const wchar_t* request_headers, 604 const wchar_t* response_headers, const wchar_t* request_headers,
651 wchar_t** additional_headers) { 605 wchar_t** additional_headers) {
652 DCHECK(worker_thread_ != NULL);
653 DLOG(INFO) << __FUNCTION__ << " " << url() << std::endl << " headers: " << 606 DLOG(INFO) << __FUNCTION__ << " " << url() << std::endl << " headers: " <<
654 std::endl << response_headers; 607 std::endl << response_headers;
655 DCHECK_EQ(PlatformThread::CurrentId(), worker_thread_->thread_id()); 608 DCHECK_EQ(thread_, PlatformThread::CurrentId());
656
657 if (!binding_) { 609 if (!binding_) {
658 DCHECK(redirect_url_.empty() == false);
659 DLOG(WARNING) << __FUNCTION__ 610 DLOG(WARNING) << __FUNCTION__
660 << ": Ignoring as the binding was aborted due to a redirect"; 611 << ": Ignoring as the binding was aborted due to a redirect";
661 return S_OK; 612 return S_OK;
662 } 613 }
663 614
664 std::string raw_headers = WideToUTF8(response_headers); 615 std::string raw_headers = WideToUTF8(response_headers);
665 616
666 // Security check for frame busting headers. We don't honor the headers 617 // Security check for frame busting headers. We don't honor the headers
667 // as-such, but instead simply kill requests which we've been asked to 618 // as-such, but instead simply kill requests which we've been asked to
668 // look for if they specify a value for "X-Frame-Options" other than 619 // look for if they specify a value for "X-Frame-Options" other than
669 // "ALLOWALL" (the others are "deny" and "sameorigin"). This puts the onus 620 // "ALLOWALL" (the others are "deny" and "sameorigin"). This puts the onus
670 // on the user of the UrlRequest to specify whether or not requests should 621 // on the user of the UrlRequest to specify whether or not requests should
671 // be inspected. For ActiveDocuments, the answer is "no", since WebKit's 622 // be inspected. For ActiveDocuments, the answer is "no", since WebKit's
672 // detection/handling is sufficient and since ActiveDocuments cannot be 623 // detection/handling is sufficient and since ActiveDocuments cannot be
673 // hosted as iframes. For NPAPI and ActiveX documents, the Initialize() 624 // hosted as iframes. For NPAPI and ActiveX documents, the Initialize()
674 // function of the PluginUrlRequest object allows them to specify how they'd 625 // function of the PluginUrlRequest object allows them to specify how they'd
675 // like requests handled. Both should set enable_frame_busting_ to true to 626 // like requests handled. Both should set enable_frame_busting_ to true to
676 // avoid CSRF attacks. Should WebKit's handling of this ever change, we will 627 // avoid CSRF attacks. Should WebKit's handling of this ever change, we will
677 // need to re-visit how and when frames are killed to better mirror a policy 628 // need to re-visit how and when frames are killed to better mirror a policy
678 // which may do something other than kill the sub-document outright. 629 // which may do something other than kill the sub-document outright.
679 630
680 // NOTE(slightlyoff): We don't use net::HttpResponseHeaders here because 631 // NOTE(slightlyoff): We don't use net::HttpResponseHeaders here because
681 // of lingering ICU/base_noicu issues. 632 // of lingering ICU/base_noicu issues.
682 if (frame_busting_enabled_) { 633 if (enable_frame_busting_) {
683 std::string http_headers = net::HttpUtil::AssembleRawHeaders( 634 std::string http_headers = net::HttpUtil::AssembleRawHeaders(
684 raw_headers.c_str(), raw_headers.length()); 635 raw_headers.c_str(), raw_headers.length());
685 if (http_utils::HasFrameBustingHeader(http_headers)) { 636 if (http_utils::HasFrameBustingHeader(http_headers)) {
686 DLOG(ERROR) << "X-Frame-Options header other than ALLOWALL " << 637 DLOG(ERROR) << "X-Frame-Options header other than ALLOWALL " <<
687 "detected, navigation canceled"; 638 "detected, navigation canceled";
688 return E_FAIL; 639 return E_FAIL;
689 } 640 }
690 } 641 }
691 642
692 std::wstring url_for_persistent_cookies =
693 redirect_url_.empty() ? UTF8ToWide(url()) : redirect_url_;
694 643
644 std::string url_for_persistent_cookies;
695 std::string persistent_cookies; 645 std::string persistent_cookies;
696 646
697 DWORD cookie_size = 0; // NOLINT 647 if (status_.was_redirected())
698 // Note that there's really no way for us here to distinguish session cookies 648 url_for_persistent_cookies = status_.get_redirection().utf8_url;
699 // from persistent cookies here. Session cookies should get filtered 649
700 // out on the chrome side as to not be added again. 650 if (url_for_persistent_cookies.empty())
701 InternetGetCookie(url_for_persistent_cookies.c_str(), NULL, NULL, 651 url_for_persistent_cookies = url();
702 &cookie_size); 652
703 if (cookie_size) { 653 // Grab cookies for the specific Url from WININET.
704 scoped_array<wchar_t> cookies(new wchar_t[cookie_size + 1]); 654 {
705 if (!InternetGetCookie(url_for_persistent_cookies.c_str(), NULL, 655 DWORD cookie_size = 0; // NOLINT
706 cookies.get(), &cookie_size)) { 656 std::wstring url = UTF8ToWide(url_for_persistent_cookies);
707 NOTREACHED() << "InternetGetCookie failed. Error: " << GetLastError(); 657
708 } else { 658 // Note that there's really no way for us here to distinguish session
709 persistent_cookies = WideToUTF8(cookies.get()); 659 // cookies from persistent cookies here. Session cookies should get
660 // filtered out on the chrome side as to not be added again.
661 InternetGetCookie(url.c_str(), NULL, NULL, &cookie_size);
662 if (cookie_size) {
663 scoped_array<wchar_t> cookies(new wchar_t[cookie_size + 1]);
664 if (!InternetGetCookie(url.c_str(), NULL, cookies.get(), &cookie_size)) {
665 NOTREACHED() << "InternetGetCookie failed. Error: " << GetLastError();
666 } else {
667 persistent_cookies = WideToUTF8(cookies.get());
668 }
710 } 669 }
711 } 670 }
712 671
713 OnResponseStarted("", 672 // Inform the delegate.
714 raw_headers.c_str(), 673 delegate_->OnResponseStarted(id(),
715 0, 674 "", // mime_type
716 base::Time(), 675 raw_headers.c_str(), // headers
676 0, // size
677 base::Time(), // last_modified
717 persistent_cookies, 678 persistent_cookies,
718 redirect_url_.empty() ? std::string() : 679 status_.get_redirection().utf8_url,
719 WideToUTF8(redirect_url_), 680 status_.get_redirection().http_code);
720 redirect_status_);
721
722 return S_OK; 681 return S_OK;
723 } 682 }
724 683
725 STDMETHODIMP UrlmonUrlRequest::GetWindow(const GUID& guid_reason, 684 STDMETHODIMP UrlmonUrlRequest::GetWindow(const GUID& guid_reason,
726 HWND* parent_window) { 685 HWND* parent_window) {
727 if (!parent_window) { 686 if (!parent_window) {
728 return E_INVALIDARG; 687 return E_INVALIDARG;
729 } 688 }
730 689
731 #ifndef NDEBUG 690 #ifndef NDEBUG
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
811 } 770 }
812 771
813 default: { 772 default: {
814 NOTREACHED() << "Unhandled security problem : " << problem; 773 NOTREACHED() << "Unhandled security problem : " << problem;
815 break; 774 break;
816 } 775 }
817 } 776 }
818 return hr; 777 return hr;
819 } 778 }
820 779
821 HRESULT UrlmonUrlRequest::ConnectToExistingMoniker(IMoniker* moniker,
822 IBindCtx* context,
823 const std::wstring& url) {
824 if (!moniker || url.empty()) {
825 NOTREACHED() << "Invalid arguments";
826 return E_INVALIDARG;
827 }
828
829 DCHECK(moniker_.get() == NULL);
830 DCHECK(bind_context_.get() == NULL);
831
832 CComObject<WrappedBindContext>* bind_context = NULL;
833 HRESULT hr = CComObject<WrappedBindContext>::CreateInstance(&bind_context);
834 if (FAILED(hr)) {
835 NOTREACHED() << "Failed to instantiate wrapped bind context. Error:" << hr;
836 return hr;
837 }
838
839 bind_context->AddRef();
840 hr = bind_context->Initialize(context);
841 DCHECK(SUCCEEDED(hr));
842
843 hr = bind_context->QueryInterface(bind_context_.Receive());
844 bind_context->Release();
845
846 if (FAILED(hr)) {
847 NOTREACHED() << "Failed to QI for IBindCtx on wrapper. Error:" << hr;
848 return hr;
849 }
850
851 moniker_ = moniker;
852 set_url(WideToUTF8(url));
853 return S_OK;
854 }
855
856 HRESULT UrlmonUrlRequest::StartAsyncDownload() { 780 HRESULT UrlmonUrlRequest::StartAsyncDownload() {
857 HRESULT hr = E_FAIL; 781 HRESULT hr = E_FAIL;
858 if (moniker_.get() == NULL) { 782 if (moniker_.get() == NULL) {
859 std::wstring wide_url = UTF8ToWide(url()); 783 std::wstring wide_url = UTF8ToWide(url());
860 hr = CreateURLMonikerEx(NULL, wide_url.c_str(), moniker_.Receive(), 784 hr = CreateURLMonikerEx(NULL, wide_url.c_str(), moniker_.Receive(),
861 URL_MK_UNIFORM); 785 URL_MK_UNIFORM);
862 if (FAILED(hr)) { 786 if (FAILED(hr)) {
863 NOTREACHED() << "CreateURLMonikerEx failed. Error: " << hr; 787 NOTREACHED() << "CreateURLMonikerEx failed. Error: " << hr;
864 } else { 788 } else {
865 hr = CreateAsyncBindCtx(0, this, NULL, bind_context_.Receive()); 789 hr = CreateAsyncBindCtx(0, this, NULL, bind_context_.Receive());
866 DCHECK(SUCCEEDED(hr)) << "CreateAsyncBindCtx failed. Error: " << hr; 790 DCHECK(SUCCEEDED(hr)) << "CreateAsyncBindCtx failed. Error: " << hr;
867 } 791 }
868 } else { 792 } else {
869 DCHECK(bind_context_.get() != NULL); 793 DCHECK(bind_context_.get() != NULL);
870 hr = RegisterBindStatusCallback(bind_context_, this, NULL, 0); 794 hr = RegisterBindStatusCallback(bind_context_, this, NULL, 0);
871 } 795 }
872 796
873 if (SUCCEEDED(hr)) { 797 if (SUCCEEDED(hr)) {
874 ScopedComPtr<IStream> stream; 798 ScopedComPtr<IStream> stream;
875 hr = moniker_->BindToStorage(bind_context_, NULL, __uuidof(IStream), 799 hr = moniker_->BindToStorage(bind_context_, NULL, __uuidof(IStream),
876 reinterpret_cast<void**>(stream.Receive())); 800 reinterpret_cast<void**>(stream.Receive()));
801 // Even if hr == S_OK, binding_ could be NULL if the entire request
802 // finish synchronously but then we still get all the callbacks etc.
803 if (hr == S_OK) {
804 DCHECK(binding_ != NULL || status_.get_state() == Status::DONE);
805 }
806
877 if (FAILED(hr)) { 807 if (FAILED(hr)) {
878 // TODO(joshia): Look into. This currently fails for: 808 // TODO(joshia): Look into. This currently fails for:
879 // http://user2:secret@localhost:1337/auth-basic?set-cookie-if-challenged 809 // http://user2:secret@localhost:1337/auth-basic?set-cookie-if-challenged
880 // when running the UrlRequest unit tests. 810 // when running the UrlRequest unit tests.
881 DLOG(ERROR) << 811 DLOG(ERROR) <<
882 StringPrintf("IUrlMoniker::BindToStorage failed. Error: 0x%08X.", hr) 812 StringPrintf("IUrlMoniker::BindToStorage failed. Error: 0x%08X.", hr)
883 << std::endl << url(); 813 << std::endl << url();
884 DCHECK(hr == MK_E_SYNTAX); 814 DCHECK(hr == MK_E_SYNTAX);
885 } 815 }
886 } 816 }
887 817
888 DLOG_IF(ERROR, FAILED(hr)) 818 DLOG_IF(ERROR, FAILED(hr))
889 << StringPrintf(L"StartAsyncDownload failed: 0x%08X", hr); 819 << StringPrintf(L"StartAsyncDownload failed: 0x%08X", hr);
890 820
891 return hr; 821 return hr;
892 } 822 }
893 823
894 void UrlmonUrlRequest::EndRequest() { 824 void UrlmonUrlRequest::NotifyDelegateAndDie() {
825 DCHECK_EQ(thread_, PlatformThread::CurrentId());
895 DLOG(INFO) << __FUNCTION__; 826 DLOG(INFO) << __FUNCTION__;
896 827 PluginUrlRequestDelegate* delegate = delegate_;
897 // In case of a redirect notification we prevent urlmon from following the 828 delegate_ = NULL;
898 // redirect and rely on Chrome, in which case AutomationMsg_RequestEnd 829 ReleaseBindings();
899 // IPC will be sent over by Chrome to end this request. 830 if (delegate) {
900 if (!ignore_redirect_stop_binding_error_) { 831 delegate->OnResponseEnd(id(), status_.get_result());
901 // Special case. If the last request was a redirect and the current OS
902 // error value is E_ACCESSDENIED, that means an unsafe redirect was
903 // attempted. In that case, correct the OS error value to be the more
904 // specific ERR_UNSAFE_REDIRECT error value.
905 if (!status_.is_success() && status_.os_error() == net::ERR_ACCESS_DENIED) {
906 int status = GetHttpResponseStatus();
907 if (status >= 300 && status < 400) {
908 redirect_status_ = status; // store the latest redirect status value.
909 status_.set_os_error(net::ERR_UNSAFE_REDIRECT);
910 }
911 }
912 OnResponseEnd(status_);
913 } else {
914 ignore_redirect_stop_binding_error_ = false;
915 } 832 }
916
917 ReleaseBindings();
918 // Remove the request mapping and release the outstanding reference to us in
919 // the context of the UI thread.
920 // We should not access any members of the UrlmonUrlRequest object after this
921 // as the object would be deleted.
922 PostTask(FROM_HERE,
923 NewRunnableMethod(this, &UrlmonUrlRequest::EndRequestInternal));
924 }
925
926 void UrlmonUrlRequest::EndRequestInternal() {
927 // The request object could have been removed from the map in the
928 // OnRequestEnd callback which executes on receiving the
929 // AutomationMsg_RequestEnd IPC from Chrome.
930 request_handler()->RemoveRequest(this);
931 // The current instance could get destroyed in the context of DestroyWindow.
932 // We should not access the object after this.
933 DestroyWindow();
934 } 833 }
935 834
936 int UrlmonUrlRequest::GetHttpResponseStatus() const { 835 int UrlmonUrlRequest::GetHttpResponseStatus() const {
937 if (binding_ == NULL) { 836 if (binding_ == NULL) {
938 DLOG(WARNING) << "GetHttpResponseStatus - no binding_"; 837 DLOG(WARNING) << "GetHttpResponseStatus - no binding_";
939 return 0; 838 return 0;
940 } 839 }
941 840
942 int http_status = 0; 841 int http_status = 0;
943 842
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after
1089 ret = net::ERR_ACCESS_DENIED; 988 ret = net::ERR_ACCESS_DENIED;
1090 break; 989 break;
1091 990
1092 default: 991 default:
1093 DLOG(WARNING) 992 DLOG(WARNING)
1094 << StringPrintf("TODO: translate HRESULT 0x%08X to net::Error", hr); 993 << StringPrintf("TODO: translate HRESULT 0x%08X to net::Error", hr);
1095 break; 994 break;
1096 } 995 }
1097 return ret; 996 return ret;
1098 } 997 }
998
999
1000 bool UrlmonUrlRequestManager::IsThreadSafe() {
1001 return true;
1002 }
1003
1004 void UrlmonUrlRequestManager::UseMonikerForUrl(IMoniker* moniker,
1005 IBindCtx* bind_ctx,
1006 const std::wstring& url) {
1007 DCHECK(NULL == moniker_for_url_.get());
1008 moniker_for_url_.reset(new MonikerForUrl());
1009 moniker_for_url_->moniker = moniker;
1010 moniker_for_url_->url = url;
1011
1012 CComObject<WrappedBindContext>* ctx = NULL;
1013 CComObject<WrappedBindContext>::CreateInstance(&ctx);
1014 ctx->Initialize(bind_ctx);
1015 ctx->QueryInterface(moniker_for_url_->bind_ctx.Receive());
1016 DCHECK(moniker_for_url_->bind_ctx.get());
1017 }
1018
1019 void UrlmonUrlRequestManager::StartRequest(int request_id,
1020 const IPC::AutomationURLRequest& request_info) {
1021 if (stopping_) {
1022 return;
1023 }
1024
1025 if (!worker_thread_.IsRunning())
1026 worker_thread_.Start();
1027
1028 MonikerForUrl* use_moniker = NULL;
1029 if (moniker_for_url_.get()) {
1030 if (GURL(moniker_for_url_->url) == GURL(request_info.url)) {
1031 use_moniker = moniker_for_url_.release();
1032 }
1033 }
1034
1035 worker_thread_.message_loop()->PostTask(FROM_HERE,
1036 NewRunnableMethod(this, &UrlmonUrlRequestManager::StartRequestWorker,
1037 request_id, request_info, use_moniker));
1038 }
1039
1040 void UrlmonUrlRequestManager::StartRequestWorker(int request_id,
1041 const IPC::AutomationURLRequest& request_info,
1042 MonikerForUrl* use_moniker) {
1043 DCHECK_EQ(worker_thread_.thread_id(), PlatformThread::CurrentId());
1044 scoped_ptr<MonikerForUrl> moniker_for_url(use_moniker);
1045
1046 if (stopping_)
1047 return;
1048
1049 DCHECK(LookupRequest(request_id).get() == NULL);
1050
1051 CComObject<UrlmonUrlRequest>* new_request = NULL;
1052 CComObject<UrlmonUrlRequest>::CreateInstance(&new_request);
1053
1054 new_request->Initialize(static_cast<PluginUrlRequestDelegate*>(this),
1055 request_id,
1056 request_info.url,
1057 request_info.method,
1058 request_info.referrer,
1059 request_info.extra_request_headers,
1060 request_info.upload_data,
1061 enable_frame_busting_);
1062
1063 // Shall we use an existing moniker?
1064 if (moniker_for_url.get()) {
1065 new_request->ConnectToExistingMoniker(moniker_for_url->moniker,
1066 moniker_for_url->bind_ctx,
1067 moniker_for_url->url);
1068 }
1069
1070 DCHECK(LookupRequest(request_id).get() == NULL);
1071 request_map_[request_id] = new_request;
1072 map_empty_.Reset();
1073
1074 new_request->Start();
1075 }
1076
1077 void UrlmonUrlRequestManager::ReadRequest(int request_id, int bytes_to_read) {
1078 if (stopping_)
1079 return;
1080
1081 worker_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this,
1082 &UrlmonUrlRequestManager::ReadRequestWorker, request_id, bytes_to_read));
1083 }
1084
1085 void UrlmonUrlRequestManager::ReadRequestWorker(int request_id,
1086 int bytes_to_read) {
1087 DCHECK_EQ(worker_thread_.thread_id(), PlatformThread::CurrentId());
1088 scoped_refptr<UrlmonUrlRequest> request = LookupRequest(request_id);
1089 // if zero, it may just have had network error.
1090 if (request) {
1091 request->Read(bytes_to_read);
1092 }
1093 }
1094
1095 void UrlmonUrlRequestManager::EndRequest(int request_id) {
1096 if (stopping_)
1097 return;
1098
1099 worker_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this,
1100 &UrlmonUrlRequestManager::EndRequestWorker, request_id));
1101 }
1102
1103 void UrlmonUrlRequestManager::EndRequestWorker(int request_id) {
1104 DCHECK_EQ(worker_thread_.thread_id(), PlatformThread::CurrentId());
1105 scoped_refptr<UrlmonUrlRequest> request = LookupRequest(request_id);
1106 if (request) {
1107 request->Stop();
1108 }
1109 }
1110
1111 void UrlmonUrlRequestManager::StopAll() {
1112 if (stopping_)
1113 return;
1114
1115 stopping_ = true;
1116
1117 if (!worker_thread_.IsRunning())
1118 return;
1119
1120 worker_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this,
1121 &UrlmonUrlRequestManager::StopAllWorker));
1122
1123 // Note we may not call worker_thread_.Stop() here. The MessageLoop's quit
1124 // task will be serialized after request::Stop tasks, but requests may
1125 // not quit immediately. CoUninitialize has a modal message loop, but it
1126 // does not help in this case.
1127 // Normally we call binding->Abort() and expect OnStopBinding() callback
1128 // where we inform UrlmonUrlRequestManager that request is dead.
1129 // The problem is that while waiting for OnStopBinding(), Quit Task may be
1130 // picked up and executed, thus exiting the thread.
1131 map_empty_.Wait();
1132 worker_thread_.Stop();
1133 DCHECK_EQ(0, UrlmonUrlRequest::instance_count_);
1134 }
1135
1136 void UrlmonUrlRequestManager::StopAllWorker() {
1137 DCHECK_EQ(worker_thread_.thread_id(), PlatformThread::CurrentId());
1138 DCHECK_EQ(true, stopping_);
1139
1140 std::vector<scoped_refptr<UrlmonUrlRequest> > request_list;
1141 // We copy the pending requests into a temporary vector as the Stop
1142 // function in the request could also try to delete the request from
1143 // the request map and the iterator could end up being invalid.
1144 for (RequestMap::iterator it = request_map_.begin();
1145 it != request_map_.end(); ++it) {
1146 DCHECK(it->second != NULL);
1147 request_list.push_back(it->second);
1148 }
1149
1150 for (std::vector<scoped_refptr<UrlmonUrlRequest> >::size_type index = 0;
1151 index < request_list.size(); ++index) {
1152 request_list[index]->Stop();
1153 }
1154 }
1155
1156 void UrlmonUrlRequestManager::OnResponseStarted(int request_id,
1157 const char* mime_type, const char* headers, int size,
1158 base::Time last_modified, const std::string& peristent_cookies,
1159 const std::string& redirect_url, int redirect_status) {
1160 DCHECK_EQ(worker_thread_.thread_id(), PlatformThread::CurrentId());
1161 DCHECK(LookupRequest(request_id).get() != NULL);
1162 delegate_->OnResponseStarted(request_id, mime_type, headers, size,
1163 last_modified, peristent_cookies, redirect_url, redirect_status);
1164 }
1165
1166 void UrlmonUrlRequestManager::OnReadComplete(int request_id, const void* buffer,
1167 int len) {
1168 DCHECK_EQ(worker_thread_.thread_id(), PlatformThread::CurrentId());
1169 DCHECK(LookupRequest(request_id).get() != NULL);
1170 delegate_->OnReadComplete(request_id, buffer, len);
1171 }
1172
1173 void UrlmonUrlRequestManager::OnResponseEnd(int request_id,
1174 const URLRequestStatus& status) {
1175 DCHECK_EQ(worker_thread_.thread_id(), PlatformThread::CurrentId());
1176 RequestMap::size_type n = request_map_.erase(request_id);
1177 DCHECK_EQ(1, n);
1178
1179 if (request_map_.size() == 0)
1180 map_empty_.Signal();
1181
1182 // Inform delegate unless the request has been explicitly cancelled.
1183 if (status.status() != URLRequestStatus::CANCELED)
1184 delegate_->OnResponseEnd(request_id, status);
1185 }
1186
1187 scoped_refptr<UrlmonUrlRequest> UrlmonUrlRequestManager::LookupRequest(
1188 int request_id) {
1189 RequestMap::iterator it = request_map_.find(request_id);
1190 if (request_map_.end() != it)
1191 return it->second;
1192 return NULL;
1193 }
1194
1195 UrlmonUrlRequestManager::UrlmonUrlRequestManager()
1196 : stopping_(false), worker_thread_("UrlMon fetch thread"),
1197 map_empty_(true, true) {
1198 }
1199
1200 UrlmonUrlRequestManager::~UrlmonUrlRequestManager() {
1201 StopAll();
1202 }
1203
1204 // Called from UI thread.
1205 void UrlmonUrlRequestManager::StealMonikerFromRequest(int request_id,
1206 IMoniker** moniker) {
1207 if (stopping_)
1208 return;
1209
1210 base::WaitableEvent done(true, false);
1211 worker_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod(this,
1212 &UrlmonUrlRequestManager::StealMonikerFromRequestWorker,
1213 request_id, moniker, &done));
1214
1215 // Wait until moniker is grabbed from a request in the worker thread.
1216 done.Wait();
1217 }
1218
1219 void UrlmonUrlRequestManager::StealMonikerFromRequestWorker(int request_id,
1220 IMoniker** moniker, base::WaitableEvent* done) {
1221 if (!stopping_) {
1222 scoped_refptr<UrlmonUrlRequest> request = LookupRequest(request_id);
1223 if (request) {
1224 request->StealMoniker(moniker);
1225 request->Stop();
1226 }
1227 }
1228
1229 done->Signal();
1230 }
OLDNEW
« no previous file with comments | « chrome_frame/urlmon_url_request.h ('k') | chrome_frame/urlmon_url_request_private.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698