OLD | NEW |
| (Empty) |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include "content/browser/renderer_host/websocket_host.h" | |
6 | |
7 #include <inttypes.h> | |
8 | |
9 #include <utility> | |
10 | |
11 #include "base/bind.h" | |
12 #include "base/bind_helpers.h" | |
13 #include "base/location.h" | |
14 #include "base/logging.h" | |
15 #include "base/macros.h" | |
16 #include "base/memory/ptr_util.h" | |
17 #include "base/single_thread_task_runner.h" | |
18 #include "base/strings/string_util.h" | |
19 #include "base/strings/stringprintf.h" | |
20 #include "base/threading/thread_task_runner_handle.h" | |
21 #include "content/browser/bad_message.h" | |
22 #include "content/browser/renderer_host/websocket_blob_sender.h" | |
23 #include "content/browser/renderer_host/websocket_dispatcher_host.h" | |
24 #include "content/browser/ssl/ssl_error_handler.h" | |
25 #include "content/browser/ssl/ssl_manager.h" | |
26 #include "content/common/websocket_messages.h" | |
27 #include "content/public/browser/browser_thread.h" | |
28 #include "content/public/browser/render_frame_host.h" | |
29 #include "content/public/browser/storage_partition.h" | |
30 #include "ipc/ipc_message_macros.h" | |
31 #include "net/base/net_errors.h" | |
32 #include "net/http/http_request_headers.h" | |
33 #include "net/http/http_response_headers.h" | |
34 #include "net/http/http_util.h" | |
35 #include "net/ssl/ssl_info.h" | |
36 #include "net/websockets/websocket_channel.h" | |
37 #include "net/websockets/websocket_errors.h" | |
38 #include "net/websockets/websocket_event_interface.h" | |
39 #include "net/websockets/websocket_frame.h" // for WebSocketFrameHeader::OpCode | |
40 #include "net/websockets/websocket_handshake_request_info.h" | |
41 #include "net/websockets/websocket_handshake_response_info.h" | |
42 #include "url/origin.h" | |
43 | |
44 namespace content { | |
45 | |
46 namespace { | |
47 | |
48 typedef net::WebSocketEventInterface::ChannelState ChannelState; | |
49 | |
50 // Convert a content::WebSocketMessageType to a | |
51 // net::WebSocketFrameHeader::OpCode | |
52 net::WebSocketFrameHeader::OpCode MessageTypeToOpCode( | |
53 WebSocketMessageType type) { | |
54 DCHECK(type == WEB_SOCKET_MESSAGE_TYPE_CONTINUATION || | |
55 type == WEB_SOCKET_MESSAGE_TYPE_TEXT || | |
56 type == WEB_SOCKET_MESSAGE_TYPE_BINARY); | |
57 typedef net::WebSocketFrameHeader::OpCode OpCode; | |
58 // These compile asserts verify that the same underlying values are used for | |
59 // both types, so we can simply cast between them. | |
60 static_assert(static_cast<OpCode>(WEB_SOCKET_MESSAGE_TYPE_CONTINUATION) == | |
61 net::WebSocketFrameHeader::kOpCodeContinuation, | |
62 "enum values must match for opcode continuation"); | |
63 static_assert(static_cast<OpCode>(WEB_SOCKET_MESSAGE_TYPE_TEXT) == | |
64 net::WebSocketFrameHeader::kOpCodeText, | |
65 "enum values must match for opcode text"); | |
66 static_assert(static_cast<OpCode>(WEB_SOCKET_MESSAGE_TYPE_BINARY) == | |
67 net::WebSocketFrameHeader::kOpCodeBinary, | |
68 "enum values must match for opcode binary"); | |
69 return static_cast<OpCode>(type); | |
70 } | |
71 | |
72 WebSocketMessageType OpCodeToMessageType( | |
73 net::WebSocketFrameHeader::OpCode opCode) { | |
74 DCHECK(opCode == net::WebSocketFrameHeader::kOpCodeContinuation || | |
75 opCode == net::WebSocketFrameHeader::kOpCodeText || | |
76 opCode == net::WebSocketFrameHeader::kOpCodeBinary); | |
77 // This cast is guaranteed valid by the static_assert() statements above. | |
78 return static_cast<WebSocketMessageType>(opCode); | |
79 } | |
80 | |
81 ChannelState StateCast(WebSocketDispatcherHost::WebSocketHostState host_state) { | |
82 const WebSocketDispatcherHost::WebSocketHostState WEBSOCKET_HOST_ALIVE = | |
83 WebSocketDispatcherHost::WEBSOCKET_HOST_ALIVE; | |
84 const WebSocketDispatcherHost::WebSocketHostState WEBSOCKET_HOST_DELETED = | |
85 WebSocketDispatcherHost::WEBSOCKET_HOST_DELETED; | |
86 | |
87 DCHECK(host_state == WEBSOCKET_HOST_ALIVE || | |
88 host_state == WEBSOCKET_HOST_DELETED); | |
89 // These compile asserts verify that we can get away with using static_cast<> | |
90 // for the conversion. | |
91 static_assert(static_cast<ChannelState>(WEBSOCKET_HOST_ALIVE) == | |
92 net::WebSocketEventInterface::CHANNEL_ALIVE, | |
93 "enum values must match for state_alive"); | |
94 static_assert(static_cast<ChannelState>(WEBSOCKET_HOST_DELETED) == | |
95 net::WebSocketEventInterface::CHANNEL_DELETED, | |
96 "enum values must match for state_deleted"); | |
97 return static_cast<ChannelState>(host_state); | |
98 } | |
99 | |
100 // Implementation of WebSocketBlobSender::Channel | |
101 class SendChannelImpl final : public WebSocketBlobSender::Channel { | |
102 public: | |
103 explicit SendChannelImpl(net::WebSocketChannel* channel) | |
104 : channel_(channel) {} | |
105 | |
106 // Implementation of WebSocketBlobSender::Channel | |
107 size_t GetSendQuota() const override { | |
108 return static_cast<size_t>(channel_->current_send_quota()); | |
109 } | |
110 | |
111 ChannelState SendFrame(bool fin, const std::vector<char>& data) override { | |
112 int opcode = first_frame_ ? net::WebSocketFrameHeader::kOpCodeBinary | |
113 : net::WebSocketFrameHeader::kOpCodeContinuation; | |
114 first_frame_ = false; | |
115 return channel_->SendFrame(fin, opcode, data); | |
116 } | |
117 | |
118 private: | |
119 net::WebSocketChannel* channel_; | |
120 bool first_frame_ = true; | |
121 | |
122 DISALLOW_COPY_AND_ASSIGN(SendChannelImpl); | |
123 }; | |
124 | |
125 } // namespace | |
126 | |
127 // Implementation of net::WebSocketEventInterface. Receives events from our | |
128 // WebSocketChannel object. Each event is translated to an IPC and sent to the | |
129 // renderer or child process via WebSocketDispatcherHost. | |
130 class WebSocketHost::WebSocketEventHandler final | |
131 : public net::WebSocketEventInterface { | |
132 public: | |
133 WebSocketEventHandler(WebSocketDispatcherHost* dispatcher, | |
134 WebSocketHost* host, | |
135 int routing_id, | |
136 int render_frame_id); | |
137 ~WebSocketEventHandler() override; | |
138 | |
139 // net::WebSocketEventInterface implementation | |
140 | |
141 ChannelState OnAddChannelResponse(const std::string& selected_subprotocol, | |
142 const std::string& extensions) override; | |
143 ChannelState OnDataFrame(bool fin, | |
144 WebSocketMessageType type, | |
145 const std::vector<char>& data) override; | |
146 ChannelState OnClosingHandshake() override; | |
147 ChannelState OnFlowControl(int64_t quota) override; | |
148 ChannelState OnDropChannel(bool was_clean, | |
149 uint16_t code, | |
150 const std::string& reason) override; | |
151 ChannelState OnFailChannel(const std::string& message) override; | |
152 ChannelState OnStartOpeningHandshake( | |
153 std::unique_ptr<net::WebSocketHandshakeRequestInfo> request) override; | |
154 ChannelState OnFinishOpeningHandshake( | |
155 std::unique_ptr<net::WebSocketHandshakeResponseInfo> response) override; | |
156 ChannelState OnSSLCertificateError( | |
157 std::unique_ptr<net::WebSocketEventInterface::SSLErrorCallbacks> | |
158 callbacks, | |
159 const GURL& url, | |
160 const net::SSLInfo& ssl_info, | |
161 bool fatal) override; | |
162 | |
163 private: | |
164 class SSLErrorHandlerDelegate final : public SSLErrorHandler::Delegate { | |
165 public: | |
166 SSLErrorHandlerDelegate( | |
167 std::unique_ptr<net::WebSocketEventInterface::SSLErrorCallbacks> | |
168 callbacks); | |
169 ~SSLErrorHandlerDelegate() override; | |
170 | |
171 base::WeakPtr<SSLErrorHandler::Delegate> GetWeakPtr(); | |
172 | |
173 // SSLErrorHandler::Delegate methods | |
174 void CancelSSLRequest(int error, const net::SSLInfo* ssl_info) override; | |
175 void ContinueSSLRequest() override; | |
176 | |
177 private: | |
178 std::unique_ptr<net::WebSocketEventInterface::SSLErrorCallbacks> callbacks_; | |
179 base::WeakPtrFactory<SSLErrorHandlerDelegate> weak_ptr_factory_; | |
180 | |
181 DISALLOW_COPY_AND_ASSIGN(SSLErrorHandlerDelegate); | |
182 }; | |
183 | |
184 WebSocketDispatcherHost* const dispatcher_; | |
185 WebSocketHost* const host_; | |
186 const int routing_id_; | |
187 const int render_frame_id_; | |
188 std::unique_ptr<SSLErrorHandlerDelegate> ssl_error_handler_delegate_; | |
189 | |
190 DISALLOW_COPY_AND_ASSIGN(WebSocketEventHandler); | |
191 }; | |
192 | |
193 WebSocketHost::WebSocketEventHandler::WebSocketEventHandler( | |
194 WebSocketDispatcherHost* dispatcher, | |
195 WebSocketHost* host, | |
196 int routing_id, | |
197 int render_frame_id) | |
198 : dispatcher_(dispatcher), | |
199 host_(host), | |
200 routing_id_(routing_id), | |
201 render_frame_id_(render_frame_id) {} | |
202 | |
203 WebSocketHost::WebSocketEventHandler::~WebSocketEventHandler() { | |
204 DVLOG(1) << "WebSocketEventHandler destroyed routing_id=" << routing_id_; | |
205 } | |
206 | |
207 ChannelState WebSocketHost::WebSocketEventHandler::OnAddChannelResponse( | |
208 const std::string& selected_protocol, | |
209 const std::string& extensions) { | |
210 DVLOG(3) << "WebSocketEventHandler::OnAddChannelResponse" | |
211 << " routing_id=" << routing_id_ | |
212 << " selected_protocol=\"" << selected_protocol << "\"" | |
213 << " extensions=\"" << extensions << "\""; | |
214 | |
215 return StateCast(dispatcher_->SendAddChannelResponse( | |
216 routing_id_, selected_protocol, extensions)); | |
217 } | |
218 | |
219 ChannelState WebSocketHost::WebSocketEventHandler::OnDataFrame( | |
220 bool fin, | |
221 net::WebSocketFrameHeader::OpCode type, | |
222 const std::vector<char>& data) { | |
223 DVLOG(3) << "WebSocketEventHandler::OnDataFrame" | |
224 << " routing_id=" << routing_id_ << " fin=" << fin | |
225 << " type=" << type << " data is " << data.size() << " bytes"; | |
226 | |
227 return StateCast(dispatcher_->SendFrame(routing_id_, fin, | |
228 OpCodeToMessageType(type), data)); | |
229 } | |
230 | |
231 ChannelState WebSocketHost::WebSocketEventHandler::OnClosingHandshake() { | |
232 DVLOG(3) << "WebSocketEventHandler::OnClosingHandshake" | |
233 << " routing_id=" << routing_id_; | |
234 | |
235 return StateCast(dispatcher_->NotifyClosingHandshake(routing_id_)); | |
236 } | |
237 | |
238 ChannelState WebSocketHost::WebSocketEventHandler::OnFlowControl( | |
239 int64_t quota) { | |
240 DVLOG(3) << "WebSocketEventHandler::OnFlowControl" | |
241 << " routing_id=" << routing_id_ << " quota=" << quota; | |
242 | |
243 if (host_->blob_sender_) | |
244 host_->blob_sender_->OnNewSendQuota(); | |
245 return StateCast(dispatcher_->SendFlowControl(routing_id_, quota)); | |
246 } | |
247 | |
248 ChannelState WebSocketHost::WebSocketEventHandler::OnDropChannel( | |
249 bool was_clean, | |
250 uint16_t code, | |
251 const std::string& reason) { | |
252 DVLOG(3) << "WebSocketEventHandler::OnDropChannel" | |
253 << " routing_id=" << routing_id_ << " was_clean=" << was_clean | |
254 << " code=" << code << " reason=\"" << reason << "\""; | |
255 | |
256 return StateCast( | |
257 dispatcher_->DoDropChannel(routing_id_, was_clean, code, reason)); | |
258 } | |
259 | |
260 ChannelState WebSocketHost::WebSocketEventHandler::OnFailChannel( | |
261 const std::string& message) { | |
262 DVLOG(3) << "WebSocketEventHandler::OnFailChannel" | |
263 << " routing_id=" << routing_id_ << " message=\"" << message << "\""; | |
264 | |
265 return StateCast(dispatcher_->NotifyFailure(routing_id_, message)); | |
266 } | |
267 | |
268 ChannelState WebSocketHost::WebSocketEventHandler::OnStartOpeningHandshake( | |
269 std::unique_ptr<net::WebSocketHandshakeRequestInfo> request) { | |
270 bool should_send = dispatcher_->CanReadRawCookies(); | |
271 DVLOG(3) << "WebSocketEventHandler::OnStartOpeningHandshake " | |
272 << "should_send=" << should_send; | |
273 | |
274 if (!should_send) | |
275 return WebSocketEventInterface::CHANNEL_ALIVE; | |
276 | |
277 WebSocketHandshakeRequest request_to_pass; | |
278 request_to_pass.url.Swap(&request->url); | |
279 net::HttpRequestHeaders::Iterator it(request->headers); | |
280 while (it.GetNext()) | |
281 request_to_pass.headers.push_back(std::make_pair(it.name(), it.value())); | |
282 request_to_pass.headers_text = | |
283 base::StringPrintf("GET %s HTTP/1.1\r\n", | |
284 request_to_pass.url.spec().c_str()) + | |
285 request->headers.ToString(); | |
286 request_to_pass.request_time = request->request_time; | |
287 | |
288 return StateCast( | |
289 dispatcher_->NotifyStartOpeningHandshake(routing_id_, request_to_pass)); | |
290 } | |
291 | |
292 ChannelState WebSocketHost::WebSocketEventHandler::OnFinishOpeningHandshake( | |
293 std::unique_ptr<net::WebSocketHandshakeResponseInfo> response) { | |
294 bool should_send = dispatcher_->CanReadRawCookies(); | |
295 DVLOG(3) << "WebSocketEventHandler::OnFinishOpeningHandshake " | |
296 << "should_send=" << should_send; | |
297 | |
298 if (!should_send) | |
299 return WebSocketEventInterface::CHANNEL_ALIVE; | |
300 | |
301 WebSocketHandshakeResponse response_to_pass; | |
302 response_to_pass.url.Swap(&response->url); | |
303 response_to_pass.status_code = response->status_code; | |
304 response_to_pass.status_text.swap(response->status_text); | |
305 size_t iter = 0; | |
306 std::string name, value; | |
307 while (response->headers->EnumerateHeaderLines(&iter, &name, &value)) | |
308 response_to_pass.headers.push_back(std::make_pair(name, value)); | |
309 response_to_pass.headers_text = | |
310 net::HttpUtil::ConvertHeadersBackToHTTPResponse( | |
311 response->headers->raw_headers()); | |
312 response_to_pass.response_time = response->response_time; | |
313 | |
314 return StateCast( | |
315 dispatcher_->NotifyFinishOpeningHandshake(routing_id_, response_to_pass)); | |
316 } | |
317 | |
318 ChannelState WebSocketHost::WebSocketEventHandler::OnSSLCertificateError( | |
319 std::unique_ptr<net::WebSocketEventInterface::SSLErrorCallbacks> callbacks, | |
320 const GURL& url, | |
321 const net::SSLInfo& ssl_info, | |
322 bool fatal) { | |
323 DVLOG(3) << "WebSocketEventHandler::OnSSLCertificateError" | |
324 << " routing_id=" << routing_id_ << " url=" << url.spec() | |
325 << " cert_status=" << ssl_info.cert_status << " fatal=" << fatal; | |
326 ssl_error_handler_delegate_.reset( | |
327 new SSLErrorHandlerDelegate(std::move(callbacks))); | |
328 SSLManager::OnSSLCertificateSubresourceError( | |
329 ssl_error_handler_delegate_->GetWeakPtr(), url, | |
330 dispatcher_->render_process_id(), render_frame_id_, ssl_info, fatal); | |
331 // The above method is always asynchronous. | |
332 return WebSocketEventInterface::CHANNEL_ALIVE; | |
333 } | |
334 | |
335 WebSocketHost::WebSocketEventHandler::SSLErrorHandlerDelegate:: | |
336 SSLErrorHandlerDelegate( | |
337 std::unique_ptr<net::WebSocketEventInterface::SSLErrorCallbacks> | |
338 callbacks) | |
339 : callbacks_(std::move(callbacks)), weak_ptr_factory_(this) {} | |
340 | |
341 WebSocketHost::WebSocketEventHandler::SSLErrorHandlerDelegate:: | |
342 ~SSLErrorHandlerDelegate() {} | |
343 | |
344 base::WeakPtr<SSLErrorHandler::Delegate> | |
345 WebSocketHost::WebSocketEventHandler::SSLErrorHandlerDelegate::GetWeakPtr() { | |
346 return weak_ptr_factory_.GetWeakPtr(); | |
347 } | |
348 | |
349 void WebSocketHost::WebSocketEventHandler::SSLErrorHandlerDelegate:: | |
350 CancelSSLRequest(int error, const net::SSLInfo* ssl_info) { | |
351 DVLOG(3) << "SSLErrorHandlerDelegate::CancelSSLRequest" | |
352 << " error=" << error | |
353 << " cert_status=" << (ssl_info ? ssl_info->cert_status | |
354 : static_cast<net::CertStatus>(-1)); | |
355 callbacks_->CancelSSLRequest(error, ssl_info); | |
356 } | |
357 | |
358 void WebSocketHost::WebSocketEventHandler::SSLErrorHandlerDelegate:: | |
359 ContinueSSLRequest() { | |
360 DVLOG(3) << "SSLErrorHandlerDelegate::ContinueSSLRequest"; | |
361 callbacks_->ContinueSSLRequest(); | |
362 } | |
363 | |
364 WebSocketHost::WebSocketHost(int routing_id, | |
365 WebSocketDispatcherHost* dispatcher, | |
366 net::URLRequestContext* url_request_context, | |
367 base::TimeDelta delay) | |
368 : dispatcher_(dispatcher), | |
369 url_request_context_(url_request_context), | |
370 routing_id_(routing_id), | |
371 delay_(delay), | |
372 pending_flow_control_quota_(0), | |
373 handshake_succeeded_(false), | |
374 weak_ptr_factory_(this) { | |
375 DVLOG(1) << "WebSocketHost: created routing_id=" << routing_id; | |
376 } | |
377 | |
378 WebSocketHost::~WebSocketHost() {} | |
379 | |
380 void WebSocketHost::GoAway() { | |
381 OnDropChannel(false, static_cast<uint16_t>(net::kWebSocketErrorGoingAway), | |
382 ""); | |
383 } | |
384 | |
385 bool WebSocketHost::OnMessageReceived(const IPC::Message& message) { | |
386 bool handled = true; | |
387 IPC_BEGIN_MESSAGE_MAP(WebSocketHost, message) | |
388 IPC_MESSAGE_HANDLER(WebSocketHostMsg_AddChannelRequest, OnAddChannelRequest) | |
389 IPC_MESSAGE_HANDLER(WebSocketHostMsg_SendBlob, OnSendBlob) | |
390 IPC_MESSAGE_HANDLER(WebSocketMsg_SendFrame, OnSendFrame) | |
391 IPC_MESSAGE_HANDLER(WebSocketMsg_FlowControl, OnFlowControl) | |
392 IPC_MESSAGE_HANDLER(WebSocketMsg_DropChannel, OnDropChannel) | |
393 IPC_MESSAGE_UNHANDLED(handled = false) | |
394 IPC_END_MESSAGE_MAP() | |
395 return handled; | |
396 } | |
397 | |
398 void WebSocketHost::OnAddChannelRequest( | |
399 const WebSocketHostMsg_AddChannelRequest_Params& params) { | |
400 DVLOG(3) << "WebSocketHost::OnAddChannelRequest" | |
401 << " routing_id=" << routing_id_ << " socket_url=\"" | |
402 << params.socket_url << "\" requested_protocols=\"" | |
403 << base::JoinString(params.requested_protocols, ", ") | |
404 << "\" origin=\"" << params.origin | |
405 << "\" first_party_for_cookies=\"" | |
406 << params.first_party_for_cookies << "\" user_agent_override=\"" | |
407 << params.user_agent_override | |
408 << "\""; | |
409 | |
410 DCHECK(!channel_); | |
411 if (delay_ > base::TimeDelta()) { | |
412 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( | |
413 FROM_HERE, | |
414 base::Bind(&WebSocketHost::AddChannel, weak_ptr_factory_.GetWeakPtr(), | |
415 params.socket_url, params.requested_protocols, | |
416 params.origin, params.first_party_for_cookies, | |
417 params.user_agent_override, params.render_frame_id), | |
418 delay_); | |
419 } else { | |
420 AddChannel( | |
421 params.socket_url, params.requested_protocols, params.origin, | |
422 params.first_party_for_cookies, params.user_agent_override, | |
423 params.render_frame_id); | |
424 } | |
425 // |this| may have been deleted here. | |
426 } | |
427 | |
428 void WebSocketHost::AddChannel( | |
429 const GURL& socket_url, | |
430 const std::vector<std::string>& requested_protocols, | |
431 const url::Origin& origin, | |
432 const GURL& first_party_for_cookies, | |
433 const std::string& user_agent_override, | |
434 int render_frame_id) { | |
435 DVLOG(3) << "WebSocketHost::AddChannel" | |
436 << " routing_id=" << routing_id_ << " socket_url=\"" << socket_url | |
437 << "\" requested_protocols=\"" | |
438 << base::JoinString(requested_protocols, ", ") << "\" origin=\"" | |
439 << origin << "\" first_party_for_cookies=\"" | |
440 << first_party_for_cookies << "\" user_agent_override=\"" | |
441 << user_agent_override << "\""; | |
442 | |
443 DCHECK(!channel_); | |
444 | |
445 std::unique_ptr<net::WebSocketEventInterface> event_interface( | |
446 new WebSocketEventHandler(dispatcher_, this, routing_id_, | |
447 render_frame_id)); | |
448 channel_.reset(new net::WebSocketChannel(std::move(event_interface), | |
449 url_request_context_)); | |
450 | |
451 if (pending_flow_control_quota_ > 0) { | |
452 // channel_->SendFlowControl(pending_flow_control_quota_) must be called | |
453 // after channel_->SendAddChannelRequest() below. | |
454 // We post OnFlowControl() here using |weak_ptr_factory_| instead of | |
455 // calling SendFlowControl directly, because |this| may have been deleted | |
456 // after channel_->SendAddChannelRequest(). | |
457 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
458 FROM_HERE, base::Bind(&WebSocketHost::OnFlowControl, | |
459 weak_ptr_factory_.GetWeakPtr(), | |
460 pending_flow_control_quota_)); | |
461 pending_flow_control_quota_ = 0; | |
462 } | |
463 | |
464 std::string additional_headers; | |
465 if (user_agent_override != "") { | |
466 if (!net::HttpUtil::IsValidHeaderValue(user_agent_override)) { | |
467 bad_message::ReceivedBadMessage( | |
468 dispatcher_, bad_message::WSH_INVALID_HEADER_VALUE); | |
469 return; | |
470 } | |
471 additional_headers = base::StringPrintf("%s:%s", | |
472 net::HttpRequestHeaders::kUserAgent, | |
473 user_agent_override.c_str()); | |
474 } | |
475 channel_->SendAddChannelRequest( | |
476 socket_url, requested_protocols, origin, first_party_for_cookies, | |
477 additional_headers); | |
478 // |this| may have been deleted here. | |
479 } | |
480 | |
481 void WebSocketHost::OnSendBlob(const std::string& uuid, | |
482 uint64_t expected_size) { | |
483 DVLOG(3) << "WebSocketHost::OnSendBlob" | |
484 << " routing_id=" << routing_id_ << " uuid=" << uuid | |
485 << " expected_size=" << expected_size; | |
486 | |
487 DCHECK(channel_); | |
488 if (blob_sender_) { | |
489 bad_message::ReceivedBadMessage( | |
490 dispatcher_, bad_message::WSH_SEND_BLOB_DURING_BLOB_SEND); | |
491 return; | |
492 } | |
493 blob_sender_.reset(new WebSocketBlobSender( | |
494 base::WrapUnique(new SendChannelImpl(channel_.get())))); | |
495 StoragePartition* partition = dispatcher_->storage_partition(); | |
496 storage::FileSystemContext* file_system_context = | |
497 partition->GetFileSystemContext(); | |
498 | |
499 net::WebSocketEventInterface::ChannelState channel_state = | |
500 net::WebSocketEventInterface::CHANNEL_ALIVE; | |
501 | |
502 // This use of base::Unretained is safe because the WebSocketBlobSender object | |
503 // is owned by this object and will not call it back after destruction. | |
504 int rv = blob_sender_->Start( | |
505 uuid, expected_size, dispatcher_->blob_storage_context(), | |
506 file_system_context, | |
507 BrowserThread::GetTaskRunnerForThread(BrowserThread::FILE).get(), | |
508 &channel_state, | |
509 base::Bind(&WebSocketHost::BlobSendComplete, base::Unretained(this))); | |
510 if (channel_state == net::WebSocketEventInterface::CHANNEL_ALIVE && | |
511 rv != net::ERR_IO_PENDING) | |
512 BlobSendComplete(rv); | |
513 // |this| may be destroyed here. | |
514 } | |
515 | |
516 void WebSocketHost::OnSendFrame(bool fin, | |
517 WebSocketMessageType type, | |
518 const std::vector<char>& data) { | |
519 DVLOG(3) << "WebSocketHost::OnSendFrame" | |
520 << " routing_id=" << routing_id_ << " fin=" << fin | |
521 << " type=" << type << " data is " << data.size() << " bytes"; | |
522 | |
523 DCHECK(channel_); | |
524 if (blob_sender_) { | |
525 bad_message::ReceivedBadMessage( | |
526 dispatcher_, bad_message::WSH_SEND_FRAME_DURING_BLOB_SEND); | |
527 return; | |
528 } | |
529 channel_->SendFrame(fin, MessageTypeToOpCode(type), data); | |
530 } | |
531 | |
532 void WebSocketHost::OnFlowControl(int64_t quota) { | |
533 DVLOG(3) << "WebSocketHost::OnFlowControl" | |
534 << " routing_id=" << routing_id_ << " quota=" << quota; | |
535 | |
536 if (!channel_) { | |
537 // WebSocketChannel is not yet created due to the delay introduced by | |
538 // per-renderer WebSocket throttling. | |
539 // SendFlowControl() is called after WebSocketChannel is created. | |
540 pending_flow_control_quota_ += quota; | |
541 return; | |
542 } | |
543 | |
544 ignore_result(channel_->SendFlowControl(quota)); | |
545 } | |
546 | |
547 void WebSocketHost::OnDropChannel(bool was_clean, | |
548 uint16_t code, | |
549 const std::string& reason) { | |
550 DVLOG(3) << "WebSocketHost::OnDropChannel" | |
551 << " routing_id=" << routing_id_ << " was_clean=" << was_clean | |
552 << " code=" << code << " reason=\"" << reason << "\""; | |
553 | |
554 if (!channel_) { | |
555 // WebSocketChannel is not yet created due to the delay introduced by | |
556 // per-renderer WebSocket throttling. | |
557 WebSocketDispatcherHost::WebSocketHostState result = | |
558 dispatcher_->DoDropChannel(routing_id_, false, | |
559 net::kWebSocketErrorAbnormalClosure, ""); | |
560 DCHECK_EQ(WebSocketDispatcherHost::WEBSOCKET_HOST_DELETED, result); | |
561 return; | |
562 } | |
563 | |
564 blob_sender_.reset(); | |
565 // TODO(yhirano): Handle |was_clean| appropriately. | |
566 ignore_result(channel_->StartClosingHandshake(code, reason)); | |
567 } | |
568 | |
569 void WebSocketHost::BlobSendComplete(int result) { | |
570 DVLOG(3) << "WebSocketHost::BlobSendComplete" | |
571 << " routing_id=" << routing_id_ | |
572 << " result=" << net::ErrorToString(result); | |
573 | |
574 // All paths through this method must reset blob_sender_, so take ownership | |
575 // at the beginning. | |
576 std::unique_ptr<WebSocketBlobSender> blob_sender(std::move(blob_sender_)); | |
577 switch (result) { | |
578 case net::OK: | |
579 ignore_result(dispatcher_->BlobSendComplete(routing_id_)); | |
580 // |this| may be destroyed here. | |
581 return; | |
582 | |
583 case net::ERR_UPLOAD_FILE_CHANGED: { | |
584 uint64_t expected_size = blob_sender->expected_size(); | |
585 uint64_t actual_size = blob_sender->ActualSize(); | |
586 if (expected_size != actual_size) { | |
587 ignore_result(dispatcher_->NotifyFailure( | |
588 routing_id_, | |
589 base::StringPrintf("Blob size mismatch; renderer size = %" PRIu64 | |
590 ", browser size = %" PRIu64, | |
591 expected_size, actual_size))); | |
592 // |this| is destroyed here. | |
593 return; | |
594 } // else fallthrough | |
595 } | |
596 | |
597 default: | |
598 ignore_result(dispatcher_->NotifyFailure( | |
599 routing_id_, | |
600 "Failed to load Blob: error code = " + net::ErrorToString(result))); | |
601 // |this| is destroyed here. | |
602 return; | |
603 } | |
604 } | |
605 | |
606 } // namespace content | |
OLD | NEW |