| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/browser/renderer_host/websocket_dispatcher_host.h" | 5 #include "content/browser/renderer_host/websocket_dispatcher_host.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 | 8 |
| 9 #include <algorithm> |
| 9 #include <string> | 10 #include <string> |
| 10 #include <vector> | 11 #include <vector> |
| 11 | 12 |
| 12 #include "base/callback.h" | 13 #include "base/callback.h" |
| 13 #include "base/logging.h" | 14 #include "base/logging.h" |
| 14 #include "base/numerics/safe_conversions.h" | 15 #include "base/numerics/safe_conversions.h" |
| 15 #include "base/rand_util.h" | 16 #include "base/rand_util.h" |
| 16 #include "base/stl_util.h" | 17 #include "base/stl_util.h" |
| 17 #include "content/browser/child_process_security_policy_impl.h" | 18 #include "content/browser/child_process_security_policy_impl.h" |
| 19 #include "content/browser/fileapi/chrome_blob_storage_context.h" |
| 18 #include "content/browser/renderer_host/websocket_host.h" | 20 #include "content/browser/renderer_host/websocket_host.h" |
| 19 #include "content/common/websocket_messages.h" | 21 #include "content/common/websocket_messages.h" |
| 20 | 22 |
| 21 namespace content { | 23 namespace content { |
| 22 | 24 |
| 23 namespace { | 25 namespace { |
| 24 | 26 |
| 25 // Many methods defined in this file return a WebSocketHostState enum | 27 // Many methods defined in this file return a WebSocketHostState enum |
| 26 // value. Make WebSocketHostState visible at file scope so it doesn't have to be | 28 // value. Make WebSocketHostState visible at file scope so it doesn't have to be |
| 27 // fully-qualified every time. | 29 // fully-qualified every time. |
| 28 typedef WebSocketDispatcherHost::WebSocketHostState WebSocketHostState; | 30 typedef WebSocketDispatcherHost::WebSocketHostState WebSocketHostState; |
| 29 | 31 |
| 30 // Max number of pending connections per WebSocketDispatcherHost | 32 // Max number of pending connections per WebSocketDispatcherHost |
| 31 // used for per-renderer WebSocket throttling. | 33 // used for per-renderer WebSocket throttling. |
| 32 const int kMaxPendingWebSocketConnections = 255; | 34 const int kMaxPendingWebSocketConnections = 255; |
| 33 | 35 |
| 34 } // namespace | 36 } // namespace |
| 35 | 37 |
| 36 WebSocketDispatcherHost::WebSocketDispatcherHost( | 38 WebSocketDispatcherHost::WebSocketDispatcherHost( |
| 37 int process_id, | 39 int process_id, |
| 38 const GetRequestContextCallback& get_context_callback) | 40 const GetRequestContextCallback& get_context_callback, |
| 41 ChromeBlobStorageContext* blob_storage_context, |
| 42 StoragePartition* storage_partition) |
| 39 : BrowserMessageFilter(WebSocketMsgStart), | 43 : BrowserMessageFilter(WebSocketMsgStart), |
| 40 process_id_(process_id), | 44 process_id_(process_id), |
| 41 get_context_callback_(get_context_callback), | 45 get_context_callback_(get_context_callback), |
| 42 websocket_host_factory_( | 46 websocket_host_factory_( |
| 43 base::Bind(&WebSocketDispatcherHost::CreateWebSocketHost, | 47 base::Bind(&WebSocketDispatcherHost::CreateWebSocketHost, |
| 44 base::Unretained(this))), | 48 base::Unretained(this))), |
| 45 num_pending_connections_(0), | 49 num_pending_connections_(0), |
| 46 num_current_succeeded_connections_(0), | 50 num_current_succeeded_connections_(0), |
| 47 num_previous_succeeded_connections_(0), | 51 num_previous_succeeded_connections_(0), |
| 48 num_current_failed_connections_(0), | 52 num_current_failed_connections_(0), |
| 49 num_previous_failed_connections_(0) {} | 53 num_previous_failed_connections_(0), |
| 54 blob_storage_context_(blob_storage_context), |
| 55 storage_partition_(storage_partition) {} |
| 50 | 56 |
| 51 WebSocketDispatcherHost::WebSocketDispatcherHost( | 57 WebSocketDispatcherHost::WebSocketDispatcherHost( |
| 52 int process_id, | 58 int process_id, |
| 53 const GetRequestContextCallback& get_context_callback, | 59 const GetRequestContextCallback& get_context_callback, |
| 54 const WebSocketHostFactory& websocket_host_factory) | 60 const WebSocketHostFactory& websocket_host_factory) |
| 55 : BrowserMessageFilter(WebSocketMsgStart), | 61 : BrowserMessageFilter(WebSocketMsgStart), |
| 56 process_id_(process_id), | 62 process_id_(process_id), |
| 57 get_context_callback_(get_context_callback), | 63 get_context_callback_(get_context_callback), |
| 58 websocket_host_factory_(websocket_host_factory), | 64 websocket_host_factory_(websocket_host_factory), |
| 59 num_pending_connections_(0), | 65 num_pending_connections_(0), |
| 60 num_current_succeeded_connections_(0), | 66 num_current_succeeded_connections_(0), |
| 61 num_previous_succeeded_connections_(0), | 67 num_previous_succeeded_connections_(0), |
| 62 num_current_failed_connections_(0), | 68 num_current_failed_connections_(0), |
| 63 num_previous_failed_connections_(0) {} | 69 num_previous_failed_connections_(0), |
| 70 storage_partition_(nullptr) {} |
| 64 | 71 |
| 65 WebSocketHost* WebSocketDispatcherHost::CreateWebSocketHost( | 72 WebSocketHost* WebSocketDispatcherHost::CreateWebSocketHost( |
| 66 int routing_id, | 73 int routing_id, |
| 67 base::TimeDelta delay) { | 74 base::TimeDelta delay) { |
| 68 return new WebSocketHost( | 75 return new WebSocketHost( |
| 69 routing_id, this, get_context_callback_.Run(), delay); | 76 routing_id, this, get_context_callback_.Run(), delay); |
| 70 } | 77 } |
| 71 | 78 |
| 72 bool WebSocketDispatcherHost::OnMessageReceived(const IPC::Message& message) { | 79 bool WebSocketDispatcherHost::OnMessageReceived(const IPC::Message& message) { |
| 73 switch (message.type()) { | 80 switch (message.type()) { |
| 74 case WebSocketHostMsg_AddChannelRequest::ID: | 81 case WebSocketHostMsg_AddChannelRequest::ID: |
| 82 case WebSocketHostMsg_SendBlob::ID: |
| 75 case WebSocketMsg_SendFrame::ID: | 83 case WebSocketMsg_SendFrame::ID: |
| 76 case WebSocketMsg_FlowControl::ID: | 84 case WebSocketMsg_FlowControl::ID: |
| 77 case WebSocketMsg_DropChannel::ID: | 85 case WebSocketMsg_DropChannel::ID: |
| 78 break; | 86 break; |
| 79 | 87 |
| 80 default: | 88 default: |
| 81 // Every message that has not been handled by a previous filter passes | 89 // Every message that has not been handled by a previous filter passes |
| 82 // through here, so it is good to pass them on as efficiently as possible. | 90 // through here, so it is good to pass them on as efficiently as possible. |
| 83 return false; | 91 return false; |
| 84 } | 92 } |
| 85 | 93 |
| 86 int routing_id = message.routing_id(); | 94 int routing_id = message.routing_id(); |
| 87 WebSocketHost* host = GetHost(routing_id); | 95 WebSocketHost* host = GetHost(routing_id); |
| 88 if (message.type() == WebSocketHostMsg_AddChannelRequest::ID) { | 96 if (message.type() == WebSocketHostMsg_AddChannelRequest::ID) { |
| 89 if (host) { | 97 if (host) { |
| 90 DVLOG(1) << "routing_id=" << routing_id << " already in use."; | 98 DVLOG(1) << "routing_id=" << routing_id << " already in use."; |
| 91 // The websocket multiplexing spec says to should drop the physical | 99 // The websocket multiplexing spec says to should drop the physical |
| 92 // connection in this case, but there isn't a real physical connection | 100 // connection in this case, but there isn't a real physical connection |
| 93 // to the renderer, and killing the renderer for this would seem to be a | 101 // to the renderer, and killing the renderer for this would seem to be a |
| 94 // little extreme. So for now just ignore the bogus request. | 102 // little extreme. So for now just ignore the bogus request. |
| 95 return true; // We handled the message (by ignoring it). | 103 return true; // We handled the message (by ignoring it). |
| 96 } | 104 } |
| 97 if (num_pending_connections_ >= kMaxPendingWebSocketConnections) { | 105 if (num_pending_connections_ >= kMaxPendingWebSocketConnections) { |
| 98 if(!Send(new WebSocketMsg_NotifyFailure(routing_id, | 106 if (!Send(new WebSocketMsg_NotifyFailure( |
| 99 "Error in connection establishment: net::ERR_INSUFFICIENT_RESOURCES" | 107 routing_id, |
| 100 ))) { | 108 "Error in connection establishment: " |
| 109 "net::ERR_INSUFFICIENT_RESOURCES"))) { |
| 101 DVLOG(1) << "Sending of message type " | 110 DVLOG(1) << "Sending of message type " |
| 102 << "WebSocketMsg_NotifyFailure failed."; | 111 << "WebSocketMsg_NotifyFailure failed."; |
| 103 } | 112 } |
| 104 return true; | 113 return true; |
| 105 } | 114 } |
| 106 host = websocket_host_factory_.Run(routing_id, CalculateDelay()); | 115 host = websocket_host_factory_.Run(routing_id, CalculateDelay()); |
| 107 hosts_.insert(WebSocketHostTable::value_type(routing_id, host)); | 116 hosts_.insert(WebSocketHostTable::value_type(routing_id, host)); |
| 108 ++num_pending_connections_; | 117 ++num_pending_connections_; |
| 109 if (!throttling_period_timer_.IsRunning()) | 118 if (!throttling_period_timer_.IsRunning()) |
| 110 throttling_period_timer_.Start( | 119 throttling_period_timer_.Start( |
| 111 FROM_HERE, | 120 FROM_HERE, |
| 112 base::TimeDelta::FromMinutes(2), | 121 base::TimeDelta::FromMinutes(2), |
| 113 this, | 122 this, |
| 114 &WebSocketDispatcherHost::ThrottlingPeriodTimerCallback); | 123 &WebSocketDispatcherHost::ThrottlingPeriodTimerCallback); |
| 115 } | 124 } |
| 116 if (!host) { | 125 if (!host) { |
| 117 DVLOG(1) << "Received invalid routing ID " << routing_id | 126 DVLOG(1) << "Received invalid routing ID " << routing_id |
| 118 << " from renderer."; | 127 << " from renderer."; |
| 119 return true; // We handled the message (by ignoring it). | 128 return true; // We handled the message (by ignoring it). |
| 120 } | 129 } |
| 121 return host->OnMessageReceived(message); | 130 return host->OnMessageReceived(message); |
| 122 } | 131 } |
| 123 | 132 |
| 124 bool WebSocketDispatcherHost::CanReadRawCookies() const { | 133 bool WebSocketDispatcherHost::CanReadRawCookies() const { |
| 125 ChildProcessSecurityPolicyImpl* policy = | 134 ChildProcessSecurityPolicyImpl* policy = |
| 126 ChildProcessSecurityPolicyImpl::GetInstance(); | 135 ChildProcessSecurityPolicyImpl::GetInstance(); |
| 127 return policy->CanReadRawCookies(process_id_); | 136 return policy->CanReadRawCookies(process_id_); |
| 128 } | 137 } |
| 129 | 138 |
| 139 storage::BlobStorageContext* WebSocketDispatcherHost::blob_storage_context() |
| 140 const { |
| 141 DCHECK(blob_storage_context_); |
| 142 return blob_storage_context_->context(); |
| 143 } |
| 144 |
| 130 WebSocketHost* WebSocketDispatcherHost::GetHost(int routing_id) const { | 145 WebSocketHost* WebSocketDispatcherHost::GetHost(int routing_id) const { |
| 131 WebSocketHostTable::const_iterator it = hosts_.find(routing_id); | 146 WebSocketHostTable::const_iterator it = hosts_.find(routing_id); |
| 132 return it == hosts_.end() ? NULL : it->second; | 147 return it == hosts_.end() ? NULL : it->second; |
| 133 } | 148 } |
| 134 | 149 |
| 135 WebSocketHostState WebSocketDispatcherHost::SendOrDrop(IPC::Message* message) { | 150 WebSocketHostState WebSocketDispatcherHost::SendOrDrop(IPC::Message* message) { |
| 136 const uint32_t message_type = message->type(); | 151 const uint32_t message_type = message->type(); |
| 137 const int32_t message_routing_id = message->routing_id(); | 152 const int32_t message_routing_id = message->routing_id(); |
| 138 if (!Send(message)) { | 153 if (!Send(message)) { |
| 139 message = NULL; | 154 message = NULL; |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 195 int routing_id, | 210 int routing_id, |
| 196 const std::string& message) { | 211 const std::string& message) { |
| 197 if (SendOrDrop(new WebSocketMsg_NotifyFailure( | 212 if (SendOrDrop(new WebSocketMsg_NotifyFailure( |
| 198 routing_id, message)) == WEBSOCKET_HOST_DELETED) { | 213 routing_id, message)) == WEBSOCKET_HOST_DELETED) { |
| 199 return WEBSOCKET_HOST_DELETED; | 214 return WEBSOCKET_HOST_DELETED; |
| 200 } | 215 } |
| 201 DeleteWebSocketHost(routing_id); | 216 DeleteWebSocketHost(routing_id); |
| 202 return WEBSOCKET_HOST_DELETED; | 217 return WEBSOCKET_HOST_DELETED; |
| 203 } | 218 } |
| 204 | 219 |
| 220 WebSocketHostState WebSocketDispatcherHost::BlobSendComplete(int routing_id) { |
| 221 return SendOrDrop(new WebSocketMsg_BlobSendComplete(routing_id)); |
| 222 } |
| 223 |
| 205 WebSocketHostState WebSocketDispatcherHost::DoDropChannel( | 224 WebSocketHostState WebSocketDispatcherHost::DoDropChannel( |
| 206 int routing_id, | 225 int routing_id, |
| 207 bool was_clean, | 226 bool was_clean, |
| 208 uint16_t code, | 227 uint16_t code, |
| 209 const std::string& reason) { | 228 const std::string& reason) { |
| 210 if (SendOrDrop( | 229 if (SendOrDrop( |
| 211 new WebSocketMsg_DropChannel(routing_id, was_clean, code, reason)) == | 230 new WebSocketMsg_DropChannel(routing_id, was_clean, code, reason)) == |
| 212 WEBSOCKET_HOST_DELETED) | 231 WEBSOCKET_HOST_DELETED) |
| 213 return WEBSOCKET_HOST_DELETED; | 232 return WEBSOCKET_HOST_DELETED; |
| 214 DeleteWebSocketHost(routing_id); | 233 DeleteWebSocketHost(routing_id); |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 282 num_current_succeeded_connections_ = 0; | 301 num_current_succeeded_connections_ = 0; |
| 283 | 302 |
| 284 if (num_pending_connections_ == 0 && | 303 if (num_pending_connections_ == 0 && |
| 285 num_previous_failed_connections_ == 0 && | 304 num_previous_failed_connections_ == 0 && |
| 286 num_previous_succeeded_connections_ == 0) { | 305 num_previous_succeeded_connections_ == 0) { |
| 287 throttling_period_timer_.Stop(); | 306 throttling_period_timer_.Stop(); |
| 288 } | 307 } |
| 289 } | 308 } |
| 290 | 309 |
| 291 } // namespace content | 310 } // namespace content |
| OLD | NEW |