OLD | NEW |
| (Empty) |
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/renderer_host/socket_stream_dispatcher_host.h" | |
6 | |
7 #include <string> | |
8 | |
9 #include "base/logging.h" | |
10 #include "content/browser/renderer_host/socket_stream_host.h" | |
11 #include "content/browser/ssl/ssl_manager.h" | |
12 #include "content/common/resource_messages.h" | |
13 #include "content/common/socket_stream.h" | |
14 #include "content/common/socket_stream_messages.h" | |
15 #include "content/public/browser/content_browser_client.h" | |
16 #include "net/base/net_errors.h" | |
17 #include "net/cookies/canonical_cookie.h" | |
18 #include "net/url_request/url_request_context_getter.h" | |
19 #include "net/websockets/websocket_job.h" | |
20 #include "net/websockets/websocket_throttle.h" | |
21 | |
22 namespace content { | |
23 | |
24 namespace { | |
25 | |
26 const size_t kMaxSocketStreamHosts = 16 * 1024; | |
27 | |
28 } // namespace | |
29 | |
30 SocketStreamDispatcherHost::SocketStreamDispatcherHost( | |
31 int render_process_id, | |
32 const GetRequestContextCallback& request_context_callback, | |
33 ResourceContext* resource_context) | |
34 : BrowserMessageFilter(SocketStreamMsgStart), | |
35 render_process_id_(render_process_id), | |
36 request_context_callback_(request_context_callback), | |
37 resource_context_(resource_context), | |
38 on_shutdown_(false) { | |
39 net::WebSocketJob::EnsureInit(); | |
40 } | |
41 | |
42 bool SocketStreamDispatcherHost::OnMessageReceived( | |
43 const IPC::Message& message) { | |
44 if (on_shutdown_) | |
45 return false; | |
46 | |
47 bool handled = true; | |
48 IPC_BEGIN_MESSAGE_MAP(SocketStreamDispatcherHost, message) | |
49 IPC_MESSAGE_HANDLER(SocketStreamHostMsg_Connect, OnConnect) | |
50 IPC_MESSAGE_HANDLER(SocketStreamHostMsg_SendData, OnSendData) | |
51 IPC_MESSAGE_HANDLER(SocketStreamHostMsg_Close, OnCloseReq) | |
52 IPC_MESSAGE_UNHANDLED(handled = false) | |
53 IPC_END_MESSAGE_MAP() | |
54 return handled; | |
55 } | |
56 | |
57 // SocketStream::Delegate methods implementations. | |
58 void SocketStreamDispatcherHost::OnConnected(net::SocketStream* socket, | |
59 int max_pending_send_allowed) { | |
60 int socket_id = SocketStreamHost::SocketIdFromSocketStream(socket); | |
61 DVLOG(2) << "SocketStreamDispatcherHost::OnConnected socket_id=" << socket_id | |
62 << " max_pending_send_allowed=" << max_pending_send_allowed; | |
63 if (socket_id == kNoSocketId) { | |
64 DVLOG(1) << "NoSocketId in OnConnected"; | |
65 return; | |
66 } | |
67 if (!Send(new SocketStreamMsg_Connected( | |
68 socket_id, max_pending_send_allowed))) { | |
69 DVLOG(1) << "SocketStreamMsg_Connected failed."; | |
70 DeleteSocketStreamHost(socket_id); | |
71 } | |
72 } | |
73 | |
74 void SocketStreamDispatcherHost::OnSentData(net::SocketStream* socket, | |
75 int amount_sent) { | |
76 int socket_id = SocketStreamHost::SocketIdFromSocketStream(socket); | |
77 DVLOG(2) << "SocketStreamDispatcherHost::OnSentData socket_id=" << socket_id | |
78 << " amount_sent=" << amount_sent; | |
79 if (socket_id == kNoSocketId) { | |
80 DVLOG(1) << "NoSocketId in OnSentData"; | |
81 return; | |
82 } | |
83 if (!Send(new SocketStreamMsg_SentData(socket_id, amount_sent))) { | |
84 DVLOG(1) << "SocketStreamMsg_SentData failed."; | |
85 DeleteSocketStreamHost(socket_id); | |
86 } | |
87 } | |
88 | |
89 void SocketStreamDispatcherHost::OnReceivedData( | |
90 net::SocketStream* socket, const char* data, int len) { | |
91 int socket_id = SocketStreamHost::SocketIdFromSocketStream(socket); | |
92 DVLOG(2) << "SocketStreamDispatcherHost::OnReceiveData socket_id=" | |
93 << socket_id; | |
94 if (socket_id == kNoSocketId) { | |
95 DVLOG(1) << "NoSocketId in OnReceivedData"; | |
96 return; | |
97 } | |
98 if (!Send(new SocketStreamMsg_ReceivedData( | |
99 socket_id, std::vector<char>(data, data + len)))) { | |
100 DVLOG(1) << "SocketStreamMsg_ReceivedData failed."; | |
101 DeleteSocketStreamHost(socket_id); | |
102 } | |
103 } | |
104 | |
105 void SocketStreamDispatcherHost::OnClose(net::SocketStream* socket) { | |
106 int socket_id = SocketStreamHost::SocketIdFromSocketStream(socket); | |
107 DVLOG(2) << "SocketStreamDispatcherHost::OnClosed socket_id=" << socket_id; | |
108 if (socket_id == kNoSocketId) { | |
109 DVLOG(1) << "NoSocketId in OnClose"; | |
110 return; | |
111 } | |
112 DeleteSocketStreamHost(socket_id); | |
113 } | |
114 | |
115 void SocketStreamDispatcherHost::OnError(const net::SocketStream* socket, | |
116 int error) { | |
117 int socket_id = SocketStreamHost::SocketIdFromSocketStream(socket); | |
118 DVLOG(2) << "SocketStreamDispatcherHost::OnError socket_id=" << socket_id; | |
119 if (socket_id == content::kNoSocketId) { | |
120 DVLOG(1) << "NoSocketId in OnError"; | |
121 return; | |
122 } | |
123 // SocketStream::Delegate::OnError() events are handled as WebSocket error | |
124 // event when user agent was required to fail WebSocket connection or the | |
125 // WebSocket connection is closed with prejudice. | |
126 if (!Send(new SocketStreamMsg_Failed(socket_id, error))) { | |
127 DVLOG(1) << "SocketStreamMsg_Failed failed."; | |
128 DeleteSocketStreamHost(socket_id); | |
129 } | |
130 } | |
131 | |
132 void SocketStreamDispatcherHost::OnSSLCertificateError( | |
133 net::SocketStream* socket, const net::SSLInfo& ssl_info, bool fatal) { | |
134 int socket_id = SocketStreamHost::SocketIdFromSocketStream(socket); | |
135 DVLOG(2) << "SocketStreamDispatcherHost::OnSSLCertificateError socket_id=" | |
136 << socket_id; | |
137 if (socket_id == kNoSocketId) { | |
138 DVLOG(1) << "NoSocketId in OnSSLCertificateError"; | |
139 return; | |
140 } | |
141 SocketStreamHost* socket_stream_host = hosts_.Lookup(socket_id); | |
142 DCHECK(socket_stream_host); | |
143 SSLManager::OnSSLCertificateError( | |
144 socket_stream_host->AsSSLErrorHandlerDelegate(), | |
145 RESOURCE_TYPE_SUB_RESOURCE, | |
146 socket->url(), render_process_id_, socket_stream_host->render_frame_id(), | |
147 ssl_info, fatal); | |
148 } | |
149 | |
150 bool SocketStreamDispatcherHost::CanGetCookies(net::SocketStream* socket, | |
151 const GURL& url) { | |
152 int socket_id = SocketStreamHost::SocketIdFromSocketStream(socket); | |
153 if (socket_id == kNoSocketId) { | |
154 return false; | |
155 } | |
156 SocketStreamHost* socket_stream_host = hosts_.Lookup(socket_id); | |
157 DCHECK(socket_stream_host); | |
158 return GetContentClient()->browser()->AllowGetCookie( | |
159 url, | |
160 url, | |
161 net::CookieList(), | |
162 resource_context_, | |
163 render_process_id_, | |
164 socket_stream_host->render_frame_id()); | |
165 } | |
166 | |
167 bool SocketStreamDispatcherHost::CanSetCookie(net::SocketStream* request, | |
168 const GURL& url, | |
169 const std::string& cookie_line, | |
170 net::CookieOptions* options) { | |
171 int socket_id = SocketStreamHost::SocketIdFromSocketStream(request); | |
172 if (socket_id == kNoSocketId) { | |
173 return false; | |
174 } | |
175 SocketStreamHost* socket_stream_host = hosts_.Lookup(socket_id); | |
176 DCHECK(socket_stream_host); | |
177 return GetContentClient()->browser()->AllowSetCookie( | |
178 url, | |
179 url, | |
180 cookie_line, | |
181 resource_context_, | |
182 render_process_id_, | |
183 socket_stream_host->render_frame_id(), | |
184 options); | |
185 } | |
186 | |
187 SocketStreamDispatcherHost::~SocketStreamDispatcherHost() { | |
188 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
189 Shutdown(); | |
190 } | |
191 | |
192 // Message handlers called by OnMessageReceived. | |
193 void SocketStreamDispatcherHost::OnConnect(int render_frame_id, | |
194 const GURL& url, | |
195 int socket_id) { | |
196 DVLOG(2) << "SocketStreamDispatcherHost::OnConnect" | |
197 << " render_frame_id=" << render_frame_id | |
198 << " url=" << url | |
199 << " socket_id=" << socket_id; | |
200 DCHECK_NE(kNoSocketId, socket_id); | |
201 | |
202 if (hosts_.size() >= kMaxSocketStreamHosts) { | |
203 if (!Send(new SocketStreamMsg_Failed(socket_id, | |
204 net::ERR_TOO_MANY_SOCKET_STREAMS))) { | |
205 DVLOG(1) << "SocketStreamMsg_Failed failed."; | |
206 } | |
207 if (!Send(new SocketStreamMsg_Closed(socket_id))) { | |
208 DVLOG(1) << "SocketStreamMsg_Closed failed."; | |
209 } | |
210 return; | |
211 } | |
212 | |
213 if (hosts_.Lookup(socket_id)) { | |
214 DVLOG(1) << "socket_id=" << socket_id << " already registered."; | |
215 return; | |
216 } | |
217 | |
218 // Note that the SocketStreamHost is responsible for checking that |url| | |
219 // is valid. | |
220 SocketStreamHost* socket_stream_host = | |
221 new SocketStreamHost(this, render_process_id_, render_frame_id, | |
222 socket_id); | |
223 hosts_.AddWithID(socket_stream_host, socket_id); | |
224 socket_stream_host->Connect(url, GetURLRequestContext()); | |
225 DVLOG(2) << "SocketStreamDispatcherHost::OnConnect -> " << socket_id; | |
226 } | |
227 | |
228 void SocketStreamDispatcherHost::OnSendData( | |
229 int socket_id, const std::vector<char>& data) { | |
230 DVLOG(2) << "SocketStreamDispatcherHost::OnSendData socket_id=" << socket_id; | |
231 SocketStreamHost* socket_stream_host = hosts_.Lookup(socket_id); | |
232 if (!socket_stream_host) { | |
233 DVLOG(1) << "socket_id=" << socket_id << " already closed."; | |
234 return; | |
235 } | |
236 if (!socket_stream_host->SendData(data)) { | |
237 // Cannot accept more data to send. | |
238 socket_stream_host->Close(); | |
239 } | |
240 } | |
241 | |
242 void SocketStreamDispatcherHost::OnCloseReq(int socket_id) { | |
243 DVLOG(2) << "SocketStreamDispatcherHost::OnCloseReq socket_id=" << socket_id; | |
244 SocketStreamHost* socket_stream_host = hosts_.Lookup(socket_id); | |
245 if (!socket_stream_host) | |
246 return; | |
247 socket_stream_host->Close(); | |
248 } | |
249 | |
250 void SocketStreamDispatcherHost::DeleteSocketStreamHost(int socket_id) { | |
251 SocketStreamHost* socket_stream_host = hosts_.Lookup(socket_id); | |
252 DCHECK(socket_stream_host); | |
253 delete socket_stream_host; | |
254 hosts_.Remove(socket_id); | |
255 if (!Send(new SocketStreamMsg_Closed(socket_id))) { | |
256 DVLOG(1) << "SocketStreamMsg_Closed failed."; | |
257 } | |
258 } | |
259 | |
260 net::URLRequestContext* SocketStreamDispatcherHost::GetURLRequestContext() { | |
261 return request_context_callback_.Run(RESOURCE_TYPE_SUB_RESOURCE); | |
262 } | |
263 | |
264 void SocketStreamDispatcherHost::Shutdown() { | |
265 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
266 // TODO(ukai): Implement IDMap::RemoveAll(). | |
267 for (IDMap<SocketStreamHost>::const_iterator iter(&hosts_); | |
268 !iter.IsAtEnd(); | |
269 iter.Advance()) { | |
270 int socket_id = iter.GetCurrentKey(); | |
271 const SocketStreamHost* socket_stream_host = iter.GetCurrentValue(); | |
272 delete socket_stream_host; | |
273 hosts_.Remove(socket_id); | |
274 } | |
275 on_shutdown_ = true; | |
276 } | |
277 | |
278 } // namespace content | |
OLD | NEW |