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