Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(893)

Side by Side Diff: Source/modules/websockets/NewWebSocketChannelImpl.cpp

Issue 22914026: [ABANDONED] Introduce blink-side bridges for the new WebSocket implementation. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « Source/modules/websockets/NewWebSocketChannelImpl.h ('k') | public/platform/Platform.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright (C) 2013 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include "config.h"
32 #include "modules/websockets/NewWebSocketChannelImpl.h"
33
34 #include "bindings/v8/ScriptCallStackFactory.h"
35 #include "core/dom/ScriptExecutionContext.h"
36 #include "core/fileapi/Blob.h"
37 #include "core/fileapi/FileReaderLoader.h"
38 #include "core/inspector/InspectorInstrumentation.h"
39 #include "core/inspector/ScriptCallStack.h"
40 #include "core/loader/UniqueIdentifier.h"
41 #include "core/platform/Logging.h"
42 #include "modules/websockets/WebSocketChannel.h"
43 #include "modules/websockets/WebSocketChannelClient.h"
44 #include "public/platform/Platform.h"
45 #include "public/platform/WebData.h"
46 #include "public/platform/WebSocketHandle.h"
47 #include "public/platform/WebString.h"
48 #include "public/platform/WebURL.h"
49 #include "public/platform/WebVector.h"
50 #include "weborigin/SecurityOrigin.h"
51 #include "wtf/ArrayBuffer.h"
52 #include "wtf/OwnPtr.h"
53 #include "wtf/PassRefPtr.h"
54 #include "wtf/RefPtr.h"
55 #include "wtf/Vector.h"
56 #include "wtf/text/WTFString.h"
57
58 // FIXME: The following notifications are not implemented:
59 // InspectorInstrument::willSendWebSocketHandshake
60 // InspectorInstrument::didReceiveWebSocketHandshakeResponse
61 // InspectorInstrument::didReceiveWebSocketFrame
62 // InspectorInstrument::didSendWebSocketFrame
63
64 using WebKit::WebSocketHandle;
65
66 namespace WebCore {
67
68 namespace {
69
70 bool isClean(int code)
71 {
72 return code == WebSocketChannel::CloseEventCodeNormalClosure
73 || (WebSocketChannel::CloseEventCodeMinimumUserDefined <= code
74 && code <= WebSocketChannel::CloseEventCodeMaximumUserDefined);
75 }
76
77 } // namespace
78
79 NewWebSocketChannelImpl::NewWebSocketChannelImpl(ScriptExecutionContext* context , WebSocketChannelClient* client, const String& sourceURL, unsigned lineNumber)
80 : m_context(context)
81 , m_handle(adoptPtr(WebKit::Platform::current()->createWebSocketHandle()))
82 , m_client(client)
83 , m_identifier(0)
84 , m_state(NotConnected)
85 , m_sendingQuota(0)
86 , m_receivedDataSizeForFlowControl(0)
87 , m_bufferedAmount(0)
88 , m_sentSizeOfTopMessage(0)
89 , m_hasAlreadyFailed(false)
90 , m_suspendState(Active)
91 , m_resumeTimer(this, &NewWebSocketChannelImpl::resumeTimerFired)
92 , m_sourceURLAtConnection(sourceURL)
93 , m_lineNumberAtConnection(lineNumber)
94 {
95 if (context->isDocument() && toDocument(context)->page()) {
96 m_identifier = createUniqueIdentifier();
97 }
98 }
99
100 void NewWebSocketChannelImpl::connect(const KURL& url, const String& protocol)
101 {
102 ASSERT(m_state == NotConnected);
103 LOG(Network, "NewWebSocketChannelImpl %p connect()", this);
104 if (m_identifier) {
105 InspectorInstrumentation::didCreateWebSocket(toDocument(m_context), m_id entifier, url, protocol);
106 }
107 m_state = Connecting;
108 m_url = url;
109 Vector<String> protocols;
110 // Since protocol is already verified and escaped, we can simply split it.
111 protocol.split(", ", true, protocols);
112 WebKit::WebVector<WebKit::WebString> webProtocols(protocols.size());
113 for (size_t i = 0; i < protocols.size(); ++i) {
114 webProtocols[i] = protocols[i];
115 }
116 m_handle->connect(url, webProtocols, m_context->securityOrigin()->toString() , this);
117
118 RefPtr<ScriptCallStack> callStack = createScriptCallStack(1, true);
119 if (callStack && callStack->size()) {
120 m_sourceURLAtConnection = callStack->at(0).sourceURL();
121 m_lineNumberAtConnection = callStack->at(0).lineNumber();
122 }
123 }
124
125 String NewWebSocketChannelImpl::subprotocol()
126 {
127 LOG(Network, "NewWebSocketChannelImpl %p subprotocol()", this);
128 return m_subprotocol;
129 }
130
131 String NewWebSocketChannelImpl::extensions()
132 {
133 LOG(Network, "NewWebSocketChannelImpl %p extensions()", this);
134 return m_extensions;
135 }
136
137 WebSocketChannel::SendResult NewWebSocketChannelImpl::send(const String& message )
138 {
139 LOG(Network, "NewWebSocketChannelImpl %p sendText(%s)", this, message.utf8() .data());
140 if (m_state != Open) {
141 return SendFail;
142 }
143 m_messages.append(Message(message));
144 sendInternal();
145 return SendSuccess;
146 }
147
148 WebSocketChannel::SendResult NewWebSocketChannelImpl::send(const Blob& blob)
149 {
150 LOG(Network, "NewWebSocketChannelImpl %p sendBlob()", this);
151 if (m_state != Open) {
152 return SendFail;
153 }
154 m_messages.append(Message(blob));
155 sendInternal();
156 return SendSuccess;
157 }
158
159 WebSocketChannel::SendResult NewWebSocketChannelImpl::send(const ArrayBuffer& bu ffer, unsigned byteOffset, unsigned byteLength)
160 {
161 LOG(Network, "NewWebSocketChannelImpl %p sendArrayBuffer(%p, %u, %u)", this, buffer.data(), byteOffset, byteLength);
162 if (m_state != Open) {
163 return SendFail;
164 }
165 // buffer.slice copies its contents.
166 m_messages.append(buffer.slice(byteOffset, byteOffset + byteLength));
167 sendInternal();
168 return SendSuccess;
169 }
170
171 unsigned long NewWebSocketChannelImpl::bufferedAmount() const
172 {
173 LOG(Network, "NewWebSocketChannelImpl %p bufferedAmount()", this);
174 return m_bufferedAmount;
175 }
176
177 void NewWebSocketChannelImpl::close(int code, const String& reason)
178 {
179 LOG(Network, "NewWebSocketChannelImpl %p close(%d, %s)", this, code, reason. utf8().data());
180 if (m_state == Closing || m_state == Closed) {
181 return;
182 }
183 ASSERT(m_handle);
184 if (m_state == Open) {
185 m_handle->close(static_cast<unsigned short>(code), reason);
186 }
187 m_state = Closing;
188 }
189
190 void NewWebSocketChannelImpl::fail(const String& reason, MessageLevel level, con st String& sourceURL, unsigned lineNumber)
191 {
192 LOG(Network, "NewWebSocketChannelImpl %p fail(%s)", this, reason.utf8().data ());
193 // m_handle and m_client can be null here.
194 const String message = "WebSocket connection to '" + m_url.elidedString() + "' failed: " + reason;
195 m_context->addConsoleMessage(JSMessageSource, level, message, sourceURL, lin eNumber);
196 if (m_identifier) {
197 InspectorInstrumentation::didReceiveWebSocketFrameError(toDocument(m_con text), m_identifier, reason);
198 }
199
200 if (m_client && !m_hasAlreadyFailed) {
201 if (m_suspendState == Active) {
202 m_client->didReceiveMessageError();
203 } else {
204 m_pendingEvents.append(PendingEvent(PendingEvent::DidReceiveError));
205 }
206 }
207 m_hasAlreadyFailed = true;
208 if (m_state == Closing || m_state == Closed) {
209 return;
210 }
211 m_state = Closed;
212 m_handle = 0;
213 unsigned short code = CloseEventCodeAbnormalClosure;
214 if (m_suspendState != Active) {
215 m_pendingEvents.append(PendingEvent(code, reason));
216 return;
217 }
218 handleDidClose(code, reason);
219 // handleDidClose can delete this object.
220 }
221
222 void NewWebSocketChannelImpl::disconnect()
223 {
224 LOG(Network, "NewWebSocketChannelImpl %p disconnect()", this);
225 if (m_state == Closed) {
226 return;
227 }
228 if (m_identifier) {
229 InspectorInstrumentation::didCloseWebSocket(toDocument(m_context), m_ide ntifier);
230 }
231 ASSERT(m_handle);
232 if (m_state != Closing) {
233 m_handle->close(CloseEventCodeAbnormalClosure, "");
234 }
235 m_state = Closed;
236 m_handle = 0;
237 m_client = 0;
238 m_pendingEvents.clear();
239 }
240
241 void NewWebSocketChannelImpl::suspend()
242 {
243 LOG(Network, "NewWebSocketChannelImpl %p suspend()", this);
244 m_suspendState = Suspended;
245 }
246
247 void NewWebSocketChannelImpl::resume()
248 {
249 LOG(Network, "NewWebSocketChannelImpl %p resume()", this);
250 m_suspendState = Resuming;
251 // Use a timer to finish this function quickly.
252 if (!m_resumeTimer.isActive()) {
253 // Protect this object until the timer fires.
254 ref();
255 m_resumeTimer.startOneShot(0);
256 }
257 }
258
259 NewWebSocketChannelImpl::Message::Message(const String& text)
260 : type(MessageTypeText)
261 , text(text.utf8(String::StrictConversionReplacingUnpairedSurrogatesWithFFFD )) { }
262
263 NewWebSocketChannelImpl::Message::Message(const Blob& blob)
264 : type(MessageTypeBlob)
265 , blob(Blob::create(blob.url(), blob.type(), blob.size())) { }
266
267 NewWebSocketChannelImpl::Message::Message(PassRefPtr<ArrayBuffer> arrayBuffer)
268 : type(MessageTypeArrayBuffer)
269 , arrayBuffer(arrayBuffer) { }
270
271 void NewWebSocketChannelImpl::sendInternal()
272 {
273 if (m_state != Open || m_blobLoader || !m_sendingQuota) {
274 return;
275 }
276 ASSERT(m_handle);
277 ASSERT(m_client);
278 unsigned long bufferedAmount = m_bufferedAmount;
279 while (!m_messages.isEmpty()) {
280 if (!m_sendingQuota) {
281 break;
282 }
283 bool final = false;
284 const Message& message = m_messages.first();
285 switch (message.type) {
286 case MessageTypeText: {
287 WebSocketHandle::MessageType type =
288 m_sentSizeOfTopMessage ? WebSocketHandle::MessageTypeContinuatio n : WebSocketHandle::MessageTypeText;
289 size_t size = std::min(static_cast<size_t>(m_sendingQuota), message. text.length() - m_sentSizeOfTopMessage);
290 final = (m_sendingQuota == size);
291 m_handle->send(type, message.text.data() + m_sentSizeOfTopMessage, s ize, final);
292 m_sentSizeOfTopMessage += size;
293 m_sendingQuota -= size;
294 break;
295 }
296 case MessageTypeBlob:
297 startLoadingBlob(*message.blob);
298 break;
299 case MessageTypeArrayBuffer: {
300 WebSocketHandle::MessageType type =
301 m_sentSizeOfTopMessage ? WebSocketHandle::MessageTypeContinuatio n : WebSocketHandle::MessageTypeBinary;
302 size_t size = std::min(static_cast<size_t>(m_sendingQuota), message. arrayBuffer->byteLength() - m_sentSizeOfTopMessage);
303 final = (m_sendingQuota == size);
304 m_handle->send(type, static_cast<const char*>(message.arrayBuffer->d ata()) + m_sentSizeOfTopMessage, size, final);
305 m_sentSizeOfTopMessage += size;
306 m_sendingQuota -= size;
307 break;
308 }
309 default:
310 ASSERT_NOT_REACHED();
311 }
312 if (m_blobLoader) {
313 break;
314 }
315 ASSERT(final || !m_sendingQuota);
316 if (final) {
317 m_messages.removeFirst();
318 m_sentSizeOfTopMessage = 0;
319 }
320 }
321 if (m_suspendState == Active && m_bufferedAmount != bufferedAmount) {
322 m_client->didUpdateBufferedAmount(m_bufferedAmount);
323 }
324 }
325
326 void NewWebSocketChannelImpl::flowControlIfNecessary()
327 {
328 if (m_state != Open) {
329 return;
330 }
331 ASSERT(m_handle);
332 if (m_receivedDataSizeForFlowControl < receivedDataSizeForFlowControlHighWat erMark) {
333 return;
334 }
335 m_handle->flowControl(m_receivedDataSizeForFlowControl);
336 m_receivedDataSizeForFlowControl = 0;
337 }
338
339 void NewWebSocketChannelImpl::didConnect(WebSocketHandle* handle, bool succeed, const WebKit::WebString& selectedProtocol, const WebKit::WebString& extensions)
340 {
341 LOG(Network, "NewWebSocketChannelImpl %p didConnect(%p, %d, %s, %s)", this, handle, succeed, selectedProtocol.utf8().data(), extensions.utf8().data());
342 if (m_state != Connecting) {
343 return;
344 }
345 ASSERT(handle == m_handle);
346 ASSERT(m_client);
347 if (!succeed) {
348 failAsError("Cannot connect to " + m_url.string() + ".");
349 // failAsError can delete this object.
350 return;
351 }
352 m_state = Open;
353 m_subprotocol = selectedProtocol;
354 m_extensions = extensions;
355 if (m_suspendState == Active) {
356 m_client->didConnect();
357 } else {
358 m_pendingEvents.append(PendingEvent(PendingEvent::DidConnectComplete));
359 }
360 }
361
362 void NewWebSocketChannelImpl::didReceiveData(WebSocketHandle* handle, WebSocketH andle::MessageType type, const char* data, size_t size, bool fin)
363 {
364 LOG(Network, "NewWebSocketChannelImpl %p didReceiveData(%p, %d, (%p, %zu), % d)", this, handle, type, data, size, fin);
365 if (m_state != Open) {
366 return;
367 }
368 ASSERT(handle == m_handle);
369 ASSERT(m_client);
370 // Non-final frames cannot be empty.
371 ASSERT(fin || size);
372 switch (type) {
373 case WebSocketHandle::MessageTypeText:
374 ASSERT(m_receivingMessageData.isEmpty());
375 m_receivingMessageTypeIsText = true;
376 break;
377 case WebSocketHandle::MessageTypeBinary:
378 ASSERT(m_receivingMessageData.isEmpty());
379 m_receivingMessageTypeIsText = false;
380 break;
381 case WebSocketHandle::MessageTypeContinuation:
382 ASSERT(!m_receivingMessageData.isEmpty());
383 break;
384 default:
385 ASSERT_NOT_REACHED();
386 break;
387 }
388 m_receivingMessageData.append(data, size);
389 m_receivedDataSizeForFlowControl += size;
390 flowControlIfNecessary();
391 if (!fin) {
392 return;
393 }
394 if (m_suspendState != Active) {
395 m_pendingEvents.append(PendingEvent(m_receivingMessageTypeIsText ? Pendi ngEvent::DidReceiveTextMessage : PendingEvent::DidReceiveBinaryMessage));
396 m_pendingEvents.last().message.swap(m_receivingMessageData);
397 return;
398 }
399 Vector<char> messageData;
400 messageData.swap(m_receivingMessageData);
401 if (m_receivingMessageTypeIsText) {
402 handleTextMessage(&messageData);
403 // handleTextMessage can delete this object.
404 } else {
405 handleBinaryMessage(&messageData);
406 }
407 }
408
409
410 void NewWebSocketChannelImpl::didClose(WebSocketHandle* handle, unsigned short c ode, const WebKit::WebString& reason)
411 {
412 // FIXME: Maybe we should notify an error to m_client for some didClose mess ages.
413 LOG(Network, "NewWebSocketChannelImpl %p didClose(%p, %d, %s)", this, code, String(reason).utf8().data());
414 if (m_state == Closed) {
415 return;
416 }
417 if (m_identifier) {
418 InspectorInstrumentation::didCloseWebSocket(toDocument(m_context), m_ide ntifier);
419 }
420 ASSERT(handle == m_handle);
421 m_handle = 0;
422 m_state = Closed;
423 if (m_suspendState != Active) {
424 m_pendingEvents.append(PendingEvent(code, reason));
425 return;
426 }
427 handleDidClose(code, reason);
428 // handleDidClose may delete this object.
429 }
430
431 void NewWebSocketChannelImpl::didFinishLoading()
432 {
433 // m_client can be invalid here.
434 LOG(Network, "NewWebSocketChannelImpl %p didFinishLoading()", this);
435 if (m_state == Open) {
436 ASSERT(m_handle);
437 // The loaded blob is always placed on m_messages[0].
438 ASSERT(m_messages.size() > 0 && m_messages.first().type == MessageTypeBl ob);
439 // We replace it with the loaded blob.
440 m_messages.first() = Message(m_blobLoader->arrayBufferResult());
441 sendInternal();
442 }
443 m_blobLoader.clear();
444
445 deref();
446 // deref() may delete this object.
447 }
448
449 void NewWebSocketChannelImpl::didFail(FileError::ErrorCode errorCode)
450 {
451 // m_client can be invalid here.
452 LOG(Network, "NewWebSocketChannelImpl %p didFail(%d)", this, errorCode);
453 m_blobLoader.clear();
454 failAsError("Failed to load Blob: error code = " + String::number(errorCode) ); // FIXME: Generate human-friendly reason message.
455 deref();
456 // deref() may delete this object.
457 }
458
459 void NewWebSocketChannelImpl::resumeTimerFired(Timer<NewWebSocketChannelImpl>*)
460 {
461 RefPtr<NewWebSocketChannelImpl> protect(this);
462 deref();
463
464 if (!m_client) {
465 ASSERT(m_state == Closed);
466 return;
467 }
468 if (m_suspendState == Suspended) {
469 return;
470 }
471 ASSERT(m_suspendState == Resuming);
472 m_suspendState = Active;
473 sendInternal();
474 flowControlIfNecessary();
475 processPendingEvents();
476 }
477
478 void NewWebSocketChannelImpl::handleTextMessage(Vector<char>* messageData)
479 {
480 ASSERT(m_suspendState == Active);
481 ASSERT(messageData);
482 String message = "";
483 if (m_receivingMessageData.size() > 0) {
484 message = String::fromUTF8(m_receivingMessageData.data(), m_receivingMes sageData.size());
485 }
486 if (message.isNull()) {
487 failAsError("Could not decode a text frame as UTF-8.");
488 } else {
489 m_client->didReceiveMessage(message);
490 }
491 }
492
493 void NewWebSocketChannelImpl::handleBinaryMessage(Vector<char>* messageData)
494 {
495 ASSERT(m_suspendState == Active);
496 ASSERT(messageData);
497 OwnPtr<Vector<char> > binaryData = adoptPtr(new Vector<char>);
498 messageData->swap(*binaryData);
499 m_client->didReceiveBinaryData(binaryData.release());
500 }
501
502 void NewWebSocketChannelImpl::handleDidClose(unsigned short code, const String& reason)
503 {
504 ASSERT(m_state == Closed);
505 ASSERT(m_suspendState == Active);
506 ASSERT(m_client);
507 WebSocketChannelClient* client = m_client;
508 m_client = 0;
509 WebSocketChannelClient::ClosingHandshakeCompletionStatus status =
510 isClean(code) ? WebSocketChannelClient::ClosingHandshakeComplete : WebSo cketChannelClient::ClosingHandshakeIncomplete;
511 client->didClose(m_bufferedAmount, status, code, reason);
512 // client->didClose may delete this object.
513 }
514
515 void NewWebSocketChannelImpl::startLoadingBlob(const Blob& blob)
516 {
517 LOG(Network, "NewWebSocketChannelImpl %p startLoadingBlob(%s)", this, blob.u rl().string().utf8().data());
518 ASSERT(!m_blobLoader);
519 // Protect this object until the loading completes or fails.
520 ref();
521
522 m_blobLoader = adoptPtr(new FileReaderLoader(FileReaderLoader::ReadAsArrayBu ffer, this));
523 m_blobLoader->start(m_context, blob);
524 }
525
526 void NewWebSocketChannelImpl::processPendingEvents()
527 {
528 RefPtr<NewWebSocketChannelImpl> protect(this);
529 ASSERT(m_suspendState == Active);
530
531 for (size_t i = 0; i < m_pendingEvents.size(); ++i) {
532 ASSERT(m_client);
533 PendingEvent& event = m_pendingEvents[i];
534 switch (event.type) {
535 case PendingEvent::DidConnectComplete:
536 m_client->didConnect();
537 break;
538 case PendingEvent::DidReceiveTextMessage:
539 handleTextMessage(&event.message);
540 // m_client can be invalid here.
541 break;
542 case PendingEvent::DidReceiveBinaryMessage:
543 handleBinaryMessage(&event.message);
544 break;
545 case PendingEvent::DidReceiveError:
546 m_client->didReceiveMessageError();
547 break;
548 case PendingEvent::DidClose: {
549 ASSERT(m_state == Closed);
550 ASSERT(!m_handle);
551 handleDidClose(event.closingCode, event.closingReason);
552 // m_client can be invalid here.
553 m_client = 0;
554 break;
555 }
556 default:
557 ASSERT_NOT_REACHED();
558 break;
559 }
560
561 if (event.type == PendingEvent::DidClose || !m_client) {
562 // Drop remaining messages.
563 break;
564 }
565 }
566 m_pendingEvents.clear();
567 }
568
569 } // namespace WebCore
OLDNEW
« no previous file with comments | « Source/modules/websockets/NewWebSocketChannelImpl.h ('k') | public/platform/Platform.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698