dom_storage_message_filter.cc revision 7d4cd473f85ac64c3747c96c277f9e506a0d2246
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 "content/browser/dom_storage/dom_storage_message_filter.h" 6 7#include "base/auto_reset.h" 8#include "base/bind.h" 9#include "base/strings/nullable_string16.h" 10#include "base/strings/utf_string_conversions.h" 11#include "base/threading/sequenced_worker_pool.h" 12#include "content/browser/dom_storage/dom_storage_context_impl.h" 13#include "content/common/dom_storage_messages.h" 14#include "content/public/browser/user_metrics.h" 15#include "googleurl/src/gurl.h" 16#include "webkit/browser/dom_storage/dom_storage_area.h" 17#include "webkit/browser/dom_storage/dom_storage_host.h" 18#include "webkit/browser/dom_storage/dom_storage_task_runner.h" 19 20namespace content { 21 22DOMStorageMessageFilter::DOMStorageMessageFilter( 23 int unused, 24 DOMStorageContextImpl* context) 25 : context_(context->context()), 26 connection_dispatching_message_for_(0) { 27} 28 29DOMStorageMessageFilter::~DOMStorageMessageFilter() { 30 DCHECK(!host_.get()); 31} 32 33void DOMStorageMessageFilter::InitializeInSequence() { 34 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO)); 35 host_.reset(new dom_storage::DomStorageHost(context_.get())); 36 context_->AddEventObserver(this); 37} 38 39void DOMStorageMessageFilter::UninitializeInSequence() { 40 // TODO(michaeln): Restore this DCHECK once crbug/166470 and crbug/164403 41 // are resolved. 42 // DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO)); 43 context_->RemoveEventObserver(this); 44 host_.reset(); 45} 46 47void DOMStorageMessageFilter::OnFilterAdded(IPC::Channel* channel) { 48 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 49 BrowserMessageFilter::OnFilterAdded(channel); 50 context_->task_runner()->PostShutdownBlockingTask( 51 FROM_HERE, 52 dom_storage::DomStorageTaskRunner::PRIMARY_SEQUENCE, 53 base::Bind(&DOMStorageMessageFilter::InitializeInSequence, this)); 54} 55 56void DOMStorageMessageFilter::OnFilterRemoved() { 57 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 58 BrowserMessageFilter::OnFilterRemoved(); 59 context_->task_runner()->PostShutdownBlockingTask( 60 FROM_HERE, 61 dom_storage::DomStorageTaskRunner::PRIMARY_SEQUENCE, 62 base::Bind(&DOMStorageMessageFilter::UninitializeInSequence, this)); 63} 64 65base::TaskRunner* DOMStorageMessageFilter::OverrideTaskRunnerForMessage( 66 const IPC::Message& message) { 67 if (IPC_MESSAGE_CLASS(message) == DOMStorageMsgStart) 68 return context_->task_runner(); 69 return NULL; 70} 71 72bool DOMStorageMessageFilter::OnMessageReceived(const IPC::Message& message, 73 bool* message_was_ok) { 74 if (IPC_MESSAGE_CLASS(message) != DOMStorageMsgStart) 75 return false; 76 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO)); 77 DCHECK(host_.get()); 78 79 bool handled = true; 80 IPC_BEGIN_MESSAGE_MAP_EX(DOMStorageMessageFilter, message, *message_was_ok) 81 IPC_MESSAGE_HANDLER(DOMStorageHostMsg_OpenStorageArea, OnOpenStorageArea) 82 IPC_MESSAGE_HANDLER(DOMStorageHostMsg_CloseStorageArea, OnCloseStorageArea) 83 IPC_MESSAGE_HANDLER(DOMStorageHostMsg_LoadStorageArea, OnLoadStorageArea) 84 IPC_MESSAGE_HANDLER(DOMStorageHostMsg_SetItem, OnSetItem) 85 IPC_MESSAGE_HANDLER(DOMStorageHostMsg_RemoveItem, OnRemoveItem) 86 IPC_MESSAGE_HANDLER(DOMStorageHostMsg_Clear, OnClear) 87 IPC_MESSAGE_HANDLER(DOMStorageHostMsg_FlushMessages, OnFlushMessages) 88 IPC_MESSAGE_UNHANDLED(handled = false) 89 IPC_END_MESSAGE_MAP() 90 return handled; 91} 92 93void DOMStorageMessageFilter::OnOpenStorageArea(int connection_id, 94 int64 namespace_id, 95 const GURL& origin) { 96 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO)); 97 if (!host_->OpenStorageArea(connection_id, namespace_id, origin)) { 98 RecordAction(UserMetricsAction("BadMessageTerminate_DSMF_1")); 99 BadMessageReceived(); 100 } 101} 102 103void DOMStorageMessageFilter::OnCloseStorageArea(int connection_id) { 104 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO)); 105 host_->CloseStorageArea(connection_id); 106} 107 108void DOMStorageMessageFilter::OnLoadStorageArea(int connection_id, 109 dom_storage::ValuesMap* map) { 110 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO)); 111 if (!host_->ExtractAreaValues(connection_id, map)) { 112 RecordAction(UserMetricsAction("BadMessageTerminate_DSMF_2")); 113 BadMessageReceived(); 114 } 115 Send(new DOMStorageMsg_AsyncOperationComplete(true)); 116} 117 118void DOMStorageMessageFilter::OnSetItem( 119 int connection_id, const string16& key, 120 const string16& value, const GURL& page_url) { 121 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO)); 122 DCHECK_EQ(0, connection_dispatching_message_for_); 123 base::AutoReset<int> auto_reset(&connection_dispatching_message_for_, 124 connection_id); 125 base::NullableString16 not_used; 126 bool success = host_->SetAreaItem(connection_id, key, value, 127 page_url, ¬_used); 128 Send(new DOMStorageMsg_AsyncOperationComplete(success)); 129} 130 131void DOMStorageMessageFilter::OnRemoveItem( 132 int connection_id, const string16& key, 133 const GURL& page_url) { 134 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO)); 135 DCHECK_EQ(0, connection_dispatching_message_for_); 136 base::AutoReset<int> auto_reset(&connection_dispatching_message_for_, 137 connection_id); 138 string16 not_used; 139 host_->RemoveAreaItem(connection_id, key, page_url, ¬_used); 140 Send(new DOMStorageMsg_AsyncOperationComplete(true)); 141} 142 143void DOMStorageMessageFilter::OnClear( 144 int connection_id, const GURL& page_url) { 145 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO)); 146 DCHECK_EQ(0, connection_dispatching_message_for_); 147 base::AutoReset<int> auto_reset(&connection_dispatching_message_for_, 148 connection_id); 149 host_->ClearArea(connection_id, page_url); 150 Send(new DOMStorageMsg_AsyncOperationComplete(true)); 151} 152 153void DOMStorageMessageFilter::OnFlushMessages() { 154 // Intentionally empty method body. 155} 156 157void DOMStorageMessageFilter::OnDomStorageItemSet( 158 const dom_storage::DomStorageArea* area, 159 const string16& key, 160 const string16& new_value, 161 const base::NullableString16& old_value, 162 const GURL& page_url) { 163 SendDomStorageEvent(area, page_url, 164 base::NullableString16(key, false), 165 base::NullableString16(new_value, false), 166 old_value); 167} 168 169void DOMStorageMessageFilter::OnDomStorageItemRemoved( 170 const dom_storage::DomStorageArea* area, 171 const string16& key, 172 const string16& old_value, 173 const GURL& page_url) { 174 SendDomStorageEvent(area, page_url, 175 base::NullableString16(key, false), 176 base::NullableString16(), 177 base::NullableString16(old_value, false)); 178} 179 180void DOMStorageMessageFilter::OnDomStorageAreaCleared( 181 const dom_storage::DomStorageArea* area, 182 const GURL& page_url) { 183 SendDomStorageEvent(area, page_url, 184 base::NullableString16(), 185 base::NullableString16(), 186 base::NullableString16()); 187} 188 189void DOMStorageMessageFilter::SendDomStorageEvent( 190 const dom_storage::DomStorageArea* area, 191 const GURL& page_url, 192 const base::NullableString16& key, 193 const base::NullableString16& new_value, 194 const base::NullableString16& old_value) { 195 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO)); 196 // Only send mutation events to processes which have the area open. 197 bool originated_in_process = connection_dispatching_message_for_ != 0; 198 if (originated_in_process || 199 host_->HasAreaOpen(area->namespace_id(), area->origin())) { 200 DOMStorageMsg_Event_Params params; 201 params.origin = area->origin(); 202 params.page_url = page_url; 203 params.connection_id = connection_dispatching_message_for_; 204 params.key = key; 205 params.new_value = new_value; 206 params.old_value = old_value; 207 params.namespace_id = area->namespace_id(); 208 Send(new DOMStorageMsg_Event(params)); 209 } 210} 211 212} // namespace content 213