1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome_frame/test/net/test_automation_resource_message_filter.h"
6
7#include "base/bind.h"
8
9TestAutomationResourceMessageFilter::TestAutomationResourceMessageFilter(
10    AutomationProvider* automation) : automation_(automation) {
11}
12
13bool TestAutomationResourceMessageFilter::Send(IPC::Message* message) {
14  return automation_->Send(message);
15}
16
17// static
18void TestAutomationResourceMessageFilter::OnRequestMessage(
19    URLRequestAutomationJob* job, IPC::Message* msg) {
20  job->OnMessage(*msg);
21  delete msg;
22}
23
24bool TestAutomationResourceMessageFilter::OnMessageReceived(
25    const IPC::Message& message) {
26  // See if we want to process this message... call the base class
27  // for filter messages, send the message to the correct thread
28  // for URL requests.
29  bool handled = false;
30  int request_id;
31  if (URLRequestAutomationJob::MayFilterMessage(message, &request_id)) {
32    base::AutoLock lock(requests_lock_);
33    RequestMap::iterator it = requests_.find(request_id);
34    if (it != requests_.end()) {
35      handled = true;
36      IPC::Message* msg = new IPC::Message(message);
37      RequestJob& job = it->second;
38
39      // SUBTLE: Why is this safe? We pass the URLRequestAutomationJob to a
40      // posted task which then takes a reference. We then release the lock,
41      // meaning we are no longer protecting access to the request_map_ which
42      // holds our last owned reference to the URLRequestAutomationJob. Thus
43      // the posted task could be the one holding the last reference.
44      //
45      // If the posted task were to be run on a thread other than the one the
46      // URLRequestAutomationJob was created on, we could destroy the job on
47      // the wrong thread (resulting in badness as URLRequestJobs must be
48      // created and destroyed on the same thread). The destruction will happen
49      // on the correct thread here since we post to job.loop_ which is set as
50      // the message loop of the current thread when RegisterRequest is invoked
51      // by URLRequestJob's constructor.
52      job.loop_->PostTask(FROM_HERE,
53                          base::Bind(OnRequestMessage, job.job_, msg));
54    }
55  } else {
56    handled = AutomationResourceMessageFilter::OnMessageReceived(message);
57  }
58  return handled;
59}
60
61// Add request to the list of outstanding requests.
62bool TestAutomationResourceMessageFilter::RegisterRequest(
63    URLRequestAutomationJob* job) {
64  // Store the request in an internal map like the parent class
65  // does, but also store the current loop pointer so we can send
66  // request messages to that loop.
67  base::AutoLock lock(requests_lock_);
68  DCHECK(requests_.end() == requests_.find(job->id()));
69  RequestJob request_job = { base::MessageLoop::current(), job };
70  requests_[job->id()] = request_job;
71  return true;
72}
73
74// Remove request from the list of outstanding requests.
75void TestAutomationResourceMessageFilter::UnRegisterRequest(
76    URLRequestAutomationJob* job) {
77  base::AutoLock lock(requests_lock_);
78  requests_.erase(job->id());
79}
80