automation_resource_message_filter.cc revision c407dc5cd9bdc5668497f21b26b09d988ab439de
1// Copyright (c) 2006-2009 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/browser/automation/automation_resource_message_filter.h" 6 7#include "base/histogram.h" 8#include "base/path_service.h" 9#include "base/stl_util-inl.h" 10#include "chrome/browser/automation/url_request_automation_job.h" 11#include "chrome/browser/net/url_request_failed_dns_job.h" 12#include "chrome/browser/net/url_request_mock_http_job.h" 13#include "chrome/browser/net/url_request_mock_util.h" 14#include "chrome/browser/net/url_request_slow_download_job.h" 15#include "chrome/browser/net/url_request_slow_http_job.h" 16#include "chrome/common/chrome_paths.h" 17#include "chrome/browser/chrome_thread.h" 18#include "chrome/test/automation/automation_messages.h" 19#include "googleurl/src/gurl.h" 20#include "net/base/cookie_store.h" 21#include "net/base/net_errors.h" 22#include "net/url_request/url_request_filter.h" 23 24AutomationResourceMessageFilter::RenderViewMap 25 AutomationResourceMessageFilter::filtered_render_views_; 26 27int AutomationResourceMessageFilter::unique_request_id_ = 1; 28 29AutomationResourceMessageFilter::AutomationResourceMessageFilter() 30 : channel_(NULL) { 31 ChromeThread::PostTask( 32 ChromeThread::IO, FROM_HERE, 33 NewRunnableFunction( 34 URLRequestAutomationJob::EnsureProtocolFactoryRegistered)); 35} 36 37AutomationResourceMessageFilter::~AutomationResourceMessageFilter() { 38} 39 40// Called on the IPC thread: 41void AutomationResourceMessageFilter::OnFilterAdded(IPC::Channel* channel) { 42 DCHECK(channel_ == NULL); 43 channel_ = channel; 44} 45 46void AutomationResourceMessageFilter::OnFilterRemoved() { 47 channel_ = NULL; 48} 49 50// Called on the IPC thread: 51void AutomationResourceMessageFilter::OnChannelConnected(int32 peer_pid) { 52} 53 54// Called on the IPC thread: 55void AutomationResourceMessageFilter::OnChannelClosing() { 56 channel_ = NULL; 57 request_map_.clear(); 58 59 // Only erase RenderViews which are associated with this 60 // AutomationResourceMessageFilter instance. 61 RenderViewMap::iterator index = filtered_render_views_.begin(); 62 while (index != filtered_render_views_.end()) { 63 const AutomationDetails& details = (*index).second; 64 if (details.filter.get() == this) { 65 filtered_render_views_.erase(index++); 66 } else { 67 index++; 68 } 69 } 70} 71 72// Called on the IPC thread: 73bool AutomationResourceMessageFilter::OnMessageReceived( 74 const IPC::Message& message) { 75 int request_id; 76 if (URLRequestAutomationJob::MayFilterMessage(message, &request_id)) { 77 RequestMap::iterator it = request_map_.find(request_id); 78 if (it != request_map_.end()) { 79 URLRequestAutomationJob* job = it->second; 80 DCHECK(job); 81 if (job) { 82 job->OnMessage(message); 83 return true; 84 } 85 } 86 } 87 88 bool handled = true; 89 IPC_BEGIN_MESSAGE_MAP(AutomationResourceMessageFilter, message) 90 IPC_MESSAGE_HANDLER(AutomationMsg_SetFilteredInet, 91 OnSetFilteredInet) 92 IPC_MESSAGE_HANDLER(AutomationMsg_GetFilteredInetHitCount, 93 OnGetFilteredInetHitCount) 94 IPC_MESSAGE_HANDLER(AutomationMsg_RecordHistograms, 95 OnRecordHistograms) 96 IPC_MESSAGE_HANDLER(AutomationMsg_GetCookiesHostResponse, 97 OnGetCookiesHostResponse) 98 IPC_MESSAGE_UNHANDLED(handled = false) 99 IPC_END_MESSAGE_MAP() 100 101 return handled; 102} 103 104// Called on the IPC thread: 105bool AutomationResourceMessageFilter::Send(IPC::Message* message) { 106 // This has to be called on the IO thread. 107 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); 108 if (!channel_) { 109 delete message; 110 return false; 111 } 112 113 return channel_->Send(message); 114} 115 116bool AutomationResourceMessageFilter::RegisterRequest( 117 URLRequestAutomationJob* job) { 118 if (!job) { 119 NOTREACHED(); 120 return false; 121 } 122 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); 123 124 // Register pending jobs in the pending request map for servicing later. 125 if (job->is_pending()) { 126 DCHECK(!ContainsKey(pending_request_map_, job->id())); 127 DCHECK(!ContainsKey(request_map_, job->id())); 128 pending_request_map_[job->id()] = job; 129 } else { 130 DCHECK(!ContainsKey(request_map_, job->id())); 131 DCHECK(!ContainsKey(pending_request_map_, job->id())); 132 request_map_[job->id()] = job; 133 } 134 135 return true; 136} 137 138void AutomationResourceMessageFilter::UnRegisterRequest( 139 URLRequestAutomationJob* job) { 140 if (!job) { 141 NOTREACHED(); 142 return; 143 } 144 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); 145 146 if (job->is_pending()) { 147 DCHECK(ContainsKey(pending_request_map_, job->id())); 148 pending_request_map_.erase(job->id()); 149 } else { 150 DCHECK(ContainsKey(request_map_, job->id())); 151 request_map_.erase(job->id()); 152 } 153} 154 155bool AutomationResourceMessageFilter::RegisterRenderView( 156 int renderer_pid, int renderer_id, int tab_handle, 157 AutomationResourceMessageFilter* filter, 158 bool pending_view) { 159 if (!renderer_pid || !renderer_id || !tab_handle) { 160 NOTREACHED(); 161 return false; 162 } 163 164 ChromeThread::PostTask( 165 ChromeThread::IO, FROM_HERE, 166 NewRunnableFunction( 167 AutomationResourceMessageFilter::RegisterRenderViewInIOThread, 168 renderer_pid, renderer_id, tab_handle, filter, pending_view)); 169 return true; 170} 171 172void AutomationResourceMessageFilter::UnRegisterRenderView( 173 int renderer_pid, int renderer_id) { 174 ChromeThread::PostTask( 175 ChromeThread::IO, FROM_HERE, 176 NewRunnableFunction( 177 AutomationResourceMessageFilter::UnRegisterRenderViewInIOThread, 178 renderer_pid, renderer_id)); 179} 180 181bool AutomationResourceMessageFilter::ResumePendingRenderView( 182 int renderer_pid, int renderer_id, int tab_handle, 183 AutomationResourceMessageFilter* filter) { 184 if (!renderer_pid || !renderer_id || !tab_handle) { 185 NOTREACHED(); 186 return false; 187 } 188 189 ChromeThread::PostTask( 190 ChromeThread::IO, FROM_HERE, 191 NewRunnableFunction( 192 AutomationResourceMessageFilter::ResumePendingRenderViewInIOThread, 193 renderer_pid, renderer_id, tab_handle, filter)); 194 return true; 195} 196 197void AutomationResourceMessageFilter::RegisterRenderViewInIOThread( 198 int renderer_pid, int renderer_id, 199 int tab_handle, AutomationResourceMessageFilter* filter, 200 bool pending_view) { 201 RenderViewMap::iterator automation_details_iter( 202 filtered_render_views_.find(RendererId(renderer_pid, renderer_id))); 203 if (automation_details_iter != filtered_render_views_.end()) { 204 DCHECK(automation_details_iter->second.ref_count > 0); 205 automation_details_iter->second.ref_count++; 206 } else { 207 filtered_render_views_[RendererId(renderer_pid, renderer_id)] = 208 AutomationDetails(tab_handle, filter, pending_view); 209 } 210} 211 212// static 213void AutomationResourceMessageFilter::UnRegisterRenderViewInIOThread( 214 int renderer_pid, int renderer_id) { 215 RenderViewMap::iterator automation_details_iter( 216 filtered_render_views_.find(RendererId(renderer_pid, renderer_id))); 217 218 if (automation_details_iter == filtered_render_views_.end()) { 219 LOG(INFO) << "UnRegisterRenderViewInIOThread: already unregistered"; 220 return; 221 } 222 223 automation_details_iter->second.ref_count--; 224 225 if (automation_details_iter->second.ref_count <= 0) { 226 filtered_render_views_.erase(RendererId(renderer_pid, renderer_id)); 227 } 228} 229 230// static 231bool AutomationResourceMessageFilter::ResumePendingRenderViewInIOThread( 232 int renderer_pid, int renderer_id, int tab_handle, 233 AutomationResourceMessageFilter* filter) { 234 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); 235 236 RenderViewMap::iterator automation_details_iter( 237 filtered_render_views_.find(RendererId(renderer_pid, renderer_id))); 238 239 if (automation_details_iter == filtered_render_views_.end()) { 240 NOTREACHED() << "Failed to find pending view for renderer pid:" 241 << renderer_pid 242 << ", render view id:" 243 << renderer_id; 244 return false; 245 } 246 247 DCHECK(automation_details_iter->second.is_pending_render_view); 248 249 AutomationResourceMessageFilter* old_filter = 250 automation_details_iter->second.filter; 251 DCHECK(old_filter != NULL); 252 253 filtered_render_views_[RendererId(renderer_pid, renderer_id)] = 254 AutomationDetails(tab_handle, filter, false); 255 256 ResumeJobsForPendingView(tab_handle, old_filter, filter); 257 return true; 258} 259 260bool AutomationResourceMessageFilter::LookupRegisteredRenderView( 261 int renderer_pid, int renderer_id, AutomationDetails* details) { 262 bool found = false; 263 RenderViewMap::iterator it = filtered_render_views_.find(RendererId( 264 renderer_pid, renderer_id)); 265 if (it != filtered_render_views_.end()) { 266 found = true; 267 if (details) 268 *details = it->second; 269 } 270 271 return found; 272} 273 274bool AutomationResourceMessageFilter::GetAutomationRequestId( 275 int request_id, int* automation_request_id) { 276 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); 277 278 RequestMap::iterator it = request_map_.begin(); 279 while (it != request_map_.end()) { 280 URLRequestAutomationJob* job = it->second; 281 DCHECK(job); 282 if (job && job->request_id() == request_id) { 283 *automation_request_id = job->id(); 284 return true; 285 } 286 it++; 287 } 288 289 return false; 290} 291 292bool AutomationResourceMessageFilter::SendDownloadRequestToHost( 293 int routing_id, int tab_handle, int request_id) { 294 int automation_request_id = 0; 295 bool valid_id = GetAutomationRequestId(request_id, &automation_request_id); 296 if (!valid_id) { 297 NOTREACHED() << "Invalid request id: " << request_id; 298 return false; 299 } 300 301 return Send(new AutomationMsg_DownloadRequestInHost(0, tab_handle, 302 automation_request_id)); 303} 304 305void AutomationResourceMessageFilter::OnSetFilteredInet(bool enable) { 306 chrome_browser_net::SetUrlRequestMocksEnabled(enable); 307} 308 309void AutomationResourceMessageFilter::OnGetFilteredInetHitCount( 310 int* hit_count) { 311 *hit_count = URLRequestFilter::GetInstance()->hit_count(); 312} 313 314void AutomationResourceMessageFilter::OnRecordHistograms( 315 const std::vector<std::string>& histogram_list) { 316 for (size_t index = 0; index < histogram_list.size(); ++index) { 317 Histogram::DeserializeHistogramInfo(histogram_list[index]); 318 } 319} 320 321void AutomationResourceMessageFilter::GetCookiesForUrl( 322 int tab_handle, const GURL& url, net::CompletionCallback* callback, 323 net::CookieStore* cookie_store) { 324 DCHECK(callback != NULL); 325 DCHECK(cookie_store != NULL); 326 327 int completion_callback_id = GetNextCompletionCallbackId(); 328 DCHECK(!ContainsKey(completion_callback_map_, completion_callback_id)); 329 330 CookieCompletionInfo cookie_info; 331 cookie_info.completion_callback = callback; 332 cookie_info.cookie_store = cookie_store; 333 334 completion_callback_map_[completion_callback_id] = cookie_info; 335 336 Send(new AutomationMsg_GetCookiesFromHost(0, tab_handle, url, 337 completion_callback_id)); 338} 339 340void AutomationResourceMessageFilter::OnGetCookiesHostResponse( 341 int tab_handle, bool success, const GURL& url, const std::string& cookies, 342 int cookie_id) { 343 CompletionCallbackMap::iterator index = 344 completion_callback_map_.find(cookie_id); 345 if (index != completion_callback_map_.end()) { 346 net::CompletionCallback* callback = index->second.completion_callback; 347 scoped_refptr<net::CookieStore> cookie_store = index->second.cookie_store; 348 349 DCHECK(callback != NULL); 350 DCHECK(cookie_store.get() != NULL); 351 352 completion_callback_map_.erase(index); 353 354 // Set the cookie in the cookie store so that the callback can read it. 355 cookie_store->SetCookieWithOptions(url, cookies, net::CookieOptions()); 356 357 Tuple1<int> params; 358 params.a = success ? net::OK : net::ERR_ACCESS_DENIED; 359 callback->RunWithParams(params); 360 361 // The cookie for this URL is only valid until it is read by the callback. 362 cookie_store->SetCookieWithOptions(url, "", net::CookieOptions()); 363 } else { 364 NOTREACHED() << "Received invalid completion callback id:" 365 << cookie_id; 366 } 367} 368 369// static 370void AutomationResourceMessageFilter::ResumeJobsForPendingView( 371 int tab_handle, 372 AutomationResourceMessageFilter* old_filter, 373 AutomationResourceMessageFilter* new_filter) { 374 DCHECK(old_filter != NULL); 375 DCHECK(new_filter != NULL); 376 377 RequestMap pending_requests = old_filter->pending_request_map_; 378 379 for (RequestMap::iterator index = old_filter->pending_request_map_.begin(); 380 index != old_filter->pending_request_map_.end(); index++) { 381 scoped_refptr<URLRequestAutomationJob> job = (*index).second; 382 DCHECK_EQ(job->message_filter(), old_filter); 383 DCHECK(job->is_pending()); 384 // StartPendingJob will register the job with the new filter. 385 job->StartPendingJob(tab_handle, new_filter); 386 } 387 388 old_filter->pending_request_map_.clear(); 389} 390