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