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 |