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