Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / modules / websockets / NewWebSocketChannelImpl.cpp
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 "core/dom/Document.h"
35 #include "core/dom/ExecutionContext.h"
36 #include "core/fileapi/FileReaderLoader.h"
37 #include "core/fileapi/FileReaderLoaderClient.h"
38 #include "core/inspector/InspectorInstrumentation.h"
39 #include "core/loader/UniqueIdentifier.h"
40 #include "modules/websockets/WebSocketChannelClient.h"
41 #include "modules/websockets/WebSocketFrame.h"
42 #include "platform/Logging.h"
43 #include "platform/weborigin/SecurityOrigin.h"
44 #include "public/platform/Platform.h"
45 #include "public/platform/WebSocketHandshakeRequestInfo.h"
46 #include "public/platform/WebSocketHandshakeResponseInfo.h"
47 #include "public/platform/WebString.h"
48 #include "public/platform/WebURL.h"
49 #include "public/platform/WebVector.h"
50
51 using blink::WebSocketHandle;
52
53 namespace WebCore {
54
55 class NewWebSocketChannelImpl::BlobLoader FINAL : public FileReaderLoaderClient {
56 public:
57     BlobLoader(PassRefPtr<BlobDataHandle>, NewWebSocketChannelImpl*);
58     virtual ~BlobLoader() { }
59
60     void cancel();
61
62     // FileReaderLoaderClient functions.
63     virtual void didStartLoading() OVERRIDE { }
64     virtual void didReceiveData() OVERRIDE { }
65     virtual void didFinishLoading() OVERRIDE;
66     virtual void didFail(FileError::ErrorCode) OVERRIDE;
67
68 private:
69     NewWebSocketChannelImpl* m_channel;
70     FileReaderLoader m_loader;
71 };
72
73 NewWebSocketChannelImpl::BlobLoader::BlobLoader(PassRefPtr<BlobDataHandle> blobDataHandle, NewWebSocketChannelImpl* channel)
74     : m_channel(channel)
75     , m_loader(FileReaderLoader::ReadAsArrayBuffer, this)
76 {
77     m_loader.start(channel->executionContext(), blobDataHandle);
78 }
79
80 void NewWebSocketChannelImpl::BlobLoader::cancel()
81 {
82     m_loader.cancel();
83     // didFail will be called immediately.
84     // |this| is deleted here.
85 }
86
87 void NewWebSocketChannelImpl::BlobLoader::didFinishLoading()
88 {
89     m_channel->didFinishLoadingBlob(m_loader.arrayBufferResult());
90     // |this| is deleted here.
91 }
92
93 void NewWebSocketChannelImpl::BlobLoader::didFail(FileError::ErrorCode errorCode)
94 {
95     m_channel->didFailLoadingBlob(errorCode);
96     // |this| is deleted here.
97 }
98
99 NewWebSocketChannelImpl::NewWebSocketChannelImpl(ExecutionContext* context, WebSocketChannelClient* client, const String& sourceURL, unsigned lineNumber)
100     : ContextLifecycleObserver(context)
101     , m_handle(adoptPtr(blink::Platform::current()->createWebSocketHandle()))
102     , m_client(client)
103     , m_identifier(0)
104     , m_sendingQuota(0)
105     , m_receivedDataSizeForFlowControl(receivedDataSizeForFlowControlHighWaterMark * 2) // initial quota
106     , m_bufferedAmount(0)
107     , m_sentSizeOfTopMessage(0)
108     , m_sourceURLAtConstruction(sourceURL)
109     , m_lineNumberAtConstruction(lineNumber)
110 {
111     if (context->isDocument() && toDocument(context)->page())
112         m_identifier = createUniqueIdentifier();
113 }
114
115 NewWebSocketChannelImpl::~NewWebSocketChannelImpl()
116 {
117     abortAsyncOperations();
118 }
119
120 void NewWebSocketChannelImpl::connect(const KURL& url, const String& protocol)
121 {
122     WTF_LOG(Network, "NewWebSocketChannelImpl %p connect()", this);
123     if (!m_handle)
124         return;
125     m_url = url;
126     Vector<String> protocols;
127     // Avoid placing an empty token in the Vector when the protocol string is
128     // empty.
129     if (!protocol.isEmpty()) {
130         // Since protocol is already verified and escaped, we can simply split
131         // it.
132         protocol.split(", ", true, protocols);
133     }
134     blink::WebVector<blink::WebString> webProtocols(protocols.size());
135     for (size_t i = 0; i < protocols.size(); ++i) {
136         webProtocols[i] = protocols[i];
137     }
138     String origin = executionContext()->securityOrigin()->toString();
139     m_handle->connect(url, webProtocols, origin, this);
140     flowControlIfNecessary();
141     if (m_identifier)
142         InspectorInstrumentation::didCreateWebSocket(document(), m_identifier, url, protocol);
143 }
144
145 String NewWebSocketChannelImpl::subprotocol()
146 {
147     WTF_LOG(Network, "NewWebSocketChannelImpl %p subprotocol()", this);
148     return m_subprotocol;
149 }
150
151 String NewWebSocketChannelImpl::extensions()
152 {
153     WTF_LOG(Network, "NewWebSocketChannelImpl %p extensions()", this);
154     return m_extensions;
155 }
156
157 WebSocketChannel::SendResult NewWebSocketChannelImpl::send(const String& message)
158 {
159     WTF_LOG(Network, "NewWebSocketChannelImpl %p sendText(%s)", this, message.utf8().data());
160     if (m_identifier) {
161         // FIXME: Change the inspector API to show the entire message instead
162         // of individual frames.
163         CString data = message.utf8();
164         WebSocketFrame frame(WebSocketFrame::OpCodeText, data.data(), data.length(), WebSocketFrame::Final | WebSocketFrame::Masked);
165         InspectorInstrumentation::didSendWebSocketFrame(document(), m_identifier, frame.opCode, frame.masked, frame.payload, frame.payloadLength);
166     }
167     m_messages.append(Message(message));
168     sendInternal();
169     return SendSuccess;
170 }
171
172 WebSocketChannel::SendResult NewWebSocketChannelImpl::send(PassRefPtr<BlobDataHandle> blobDataHandle)
173 {
174     WTF_LOG(Network, "NewWebSocketChannelImpl %p sendBlob(%s, %s, %llu)", this, blobDataHandle->uuid().utf8().data(), blobDataHandle->type().utf8().data(), blobDataHandle->size());
175     if (m_identifier) {
176         // FIXME: Change the inspector API to show the entire message instead
177         // of individual frames.
178         // FIXME: We can't access the data here.
179         // Since Binary data are not displayed in Inspector, this does not
180         // affect actual behavior.
181         WebSocketFrame frame(WebSocketFrame::OpCodeBinary, "", 0, WebSocketFrame::Final | WebSocketFrame::Masked);
182         InspectorInstrumentation::didSendWebSocketFrame(document(), m_identifier, frame.opCode, frame.masked, frame.payload, frame.payloadLength);
183     }
184     m_messages.append(Message(blobDataHandle));
185     sendInternal();
186     return SendSuccess;
187 }
188
189 WebSocketChannel::SendResult NewWebSocketChannelImpl::send(const ArrayBuffer& buffer, unsigned byteOffset, unsigned byteLength)
190 {
191     WTF_LOG(Network, "NewWebSocketChannelImpl %p sendArrayBuffer(%p, %u, %u)", this, buffer.data(), byteOffset, byteLength);
192     if (m_identifier) {
193         // FIXME: Change the inspector API to show the entire message instead
194         // of individual frames.
195         WebSocketFrame frame(WebSocketFrame::OpCodeBinary, static_cast<const char*>(buffer.data()) + byteOffset, byteLength, WebSocketFrame::Final | WebSocketFrame::Masked);
196         InspectorInstrumentation::didSendWebSocketFrame(document(), m_identifier, frame.opCode, frame.masked, frame.payload, frame.payloadLength);
197     }
198     // buffer.slice copies its contents.
199     m_messages.append(buffer.slice(byteOffset, byteOffset + byteLength));
200     sendInternal();
201     return SendSuccess;
202 }
203
204 unsigned long NewWebSocketChannelImpl::bufferedAmount() const
205 {
206     WTF_LOG(Network, "NewWebSocketChannelImpl %p bufferedAmount()", this);
207     return m_bufferedAmount;
208 }
209
210 void NewWebSocketChannelImpl::close(int code, const String& reason)
211 {
212     WTF_LOG(Network, "NewWebSocketChannelImpl %p close(%d, %s)", this, code, reason.utf8().data());
213     ASSERT(m_handle);
214     m_handle->close(static_cast<unsigned short>(code), reason);
215 }
216
217 void NewWebSocketChannelImpl::fail(const String& reason, MessageLevel level, const String& sourceURL, unsigned lineNumber)
218 {
219     WTF_LOG(Network, "NewWebSocketChannelImpl %p fail(%s)", this, reason.utf8().data());
220     // m_handle and m_client can be null here.
221
222     if (m_identifier)
223         InspectorInstrumentation::didReceiveWebSocketFrameError(document(), m_identifier, reason);
224     const String message = "WebSocket connection to '" + m_url.elidedString() + "' failed: " + reason;
225     executionContext()->addConsoleMessage(JSMessageSource, level, message, sourceURL, lineNumber);
226
227     if (m_client)
228         m_client->didReceiveMessageError();
229     // |reason| is only for logging and should not be provided for scripts,
230     // hence close reason must be empty.
231     handleDidClose(false, CloseEventCodeAbnormalClosure, String());
232     // handleDidClose may delete this object.
233 }
234
235 void NewWebSocketChannelImpl::disconnect()
236 {
237     WTF_LOG(Network, "NewWebSocketChannelImpl %p disconnect()", this);
238     if (m_identifier)
239         InspectorInstrumentation::didCloseWebSocket(document(), m_identifier);
240     abortAsyncOperations();
241     m_handle.clear();
242     m_client = 0;
243     m_identifier = 0;
244 }
245
246 void NewWebSocketChannelImpl::suspend()
247 {
248     WTF_LOG(Network, "NewWebSocketChannelImpl %p suspend()", this);
249 }
250
251 void NewWebSocketChannelImpl::resume()
252 {
253     WTF_LOG(Network, "NewWebSocketChannelImpl %p resume()", this);
254 }
255
256 NewWebSocketChannelImpl::Message::Message(const String& text)
257     : type(MessageTypeText)
258     , text(text.utf8(StrictUTF8ConversionReplacingUnpairedSurrogatesWithFFFD)) { }
259
260 NewWebSocketChannelImpl::Message::Message(PassRefPtr<BlobDataHandle> blobDataHandle)
261     : type(MessageTypeBlob)
262     , blobDataHandle(blobDataHandle) { }
263
264 NewWebSocketChannelImpl::Message::Message(PassRefPtr<ArrayBuffer> arrayBuffer)
265     : type(MessageTypeArrayBuffer)
266     , arrayBuffer(arrayBuffer) { }
267
268 void NewWebSocketChannelImpl::sendInternal()
269 {
270     ASSERT(m_handle);
271     unsigned long bufferedAmount = m_bufferedAmount;
272     while (!m_messages.isEmpty() && m_sendingQuota > 0 && !m_blobLoader) {
273         bool final = false;
274         const Message& message = m_messages.first();
275         switch (message.type) {
276         case MessageTypeText: {
277             WebSocketHandle::MessageType type =
278                 m_sentSizeOfTopMessage ? WebSocketHandle::MessageTypeContinuation : WebSocketHandle::MessageTypeText;
279             size_t size = std::min(static_cast<size_t>(m_sendingQuota), message.text.length() - m_sentSizeOfTopMessage);
280             final = (m_sentSizeOfTopMessage + size == message.text.length());
281             m_handle->send(final, type, message.text.data() + m_sentSizeOfTopMessage, size);
282             m_sentSizeOfTopMessage += size;
283             m_sendingQuota -= size;
284             break;
285         }
286         case MessageTypeBlob:
287             ASSERT(!m_blobLoader);
288             m_blobLoader = adoptPtr(new BlobLoader(message.blobDataHandle, this));
289             break;
290         case MessageTypeArrayBuffer: {
291             WebSocketHandle::MessageType type =
292                 m_sentSizeOfTopMessage ? WebSocketHandle::MessageTypeContinuation : WebSocketHandle::MessageTypeBinary;
293             size_t size = std::min(static_cast<size_t>(m_sendingQuota), message.arrayBuffer->byteLength() - m_sentSizeOfTopMessage);
294             final = (m_sentSizeOfTopMessage + size == message.arrayBuffer->byteLength());
295             m_handle->send(final, type, static_cast<const char*>(message.arrayBuffer->data()) + m_sentSizeOfTopMessage, size);
296             m_sentSizeOfTopMessage += size;
297             m_sendingQuota -= size;
298             break;
299         }
300         }
301         if (final) {
302             m_messages.removeFirst();
303             m_sentSizeOfTopMessage = 0;
304         }
305     }
306     if (m_client && m_bufferedAmount != bufferedAmount) {
307         m_client->didUpdateBufferedAmount(m_bufferedAmount);
308     }
309 }
310
311 void NewWebSocketChannelImpl::flowControlIfNecessary()
312 {
313     if (!m_handle || m_receivedDataSizeForFlowControl < receivedDataSizeForFlowControlHighWaterMark) {
314         return;
315     }
316     m_handle->flowControl(m_receivedDataSizeForFlowControl);
317     m_receivedDataSizeForFlowControl = 0;
318 }
319
320 void NewWebSocketChannelImpl::abortAsyncOperations()
321 {
322     if (m_blobLoader) {
323         m_blobLoader->cancel();
324         m_blobLoader.clear();
325     }
326 }
327
328 void NewWebSocketChannelImpl::handleDidClose(bool wasClean, unsigned short code, const String& reason)
329 {
330     m_handle.clear();
331     abortAsyncOperations();
332     if (!m_client) {
333         return;
334     }
335     WebSocketChannelClient* client = m_client;
336     m_client = 0;
337     WebSocketChannelClient::ClosingHandshakeCompletionStatus status =
338         wasClean ? WebSocketChannelClient::ClosingHandshakeComplete : WebSocketChannelClient::ClosingHandshakeIncomplete;
339     client->didClose(m_bufferedAmount, status, code, reason);
340     // client->didClose may delete this object.
341 }
342
343 Document* NewWebSocketChannelImpl::document()
344 {
345     ASSERT(m_identifier);
346     ExecutionContext* context = executionContext();
347     ASSERT(context->isDocument());
348     return toDocument(context);
349 }
350
351 void NewWebSocketChannelImpl::didConnect(WebSocketHandle* handle, bool fail, const blink::WebString& selectedProtocol, const blink::WebString& extensions)
352 {
353     WTF_LOG(Network, "NewWebSocketChannelImpl %p didConnect(%p, %d, %s, %s)", this, handle, fail, selectedProtocol.utf8().data(), extensions.utf8().data());
354     ASSERT(m_handle);
355     ASSERT(handle == m_handle);
356     ASSERT(m_client);
357     if (fail) {
358         failAsError("Cannot connect to " + m_url.string() + ".");
359         // failAsError may delete this object.
360         return;
361     }
362     m_subprotocol = selectedProtocol;
363     m_extensions = extensions;
364     m_client->didConnect();
365 }
366
367 void NewWebSocketChannelImpl::didStartOpeningHandshake(WebSocketHandle* handle, const blink::WebSocketHandshakeRequestInfo& request)
368 {
369     WTF_LOG(Network, "NewWebSocketChannelImpl %p didStartOpeningHandshake(%p)", this, handle);
370     if (m_identifier)
371         InspectorInstrumentation::willSendWebSocketHandshakeRequest(document(), m_identifier, request.toCoreRequest());
372 }
373
374 void NewWebSocketChannelImpl::didFinishOpeningHandshake(WebSocketHandle* handle, const blink::WebSocketHandshakeResponseInfo& response)
375 {
376     WTF_LOG(Network, "NewWebSocketChannelImpl %p didFinishOpeningHandshake(%p)", this, handle);
377     if (m_identifier)
378         InspectorInstrumentation::didReceiveWebSocketHandshakeResponse(document(), m_identifier, response.toCoreResponse());
379 }
380
381 void NewWebSocketChannelImpl::didFail(WebSocketHandle* handle, const blink::WebString& message)
382 {
383     WTF_LOG(Network, "NewWebSocketChannelImpl %p didFail(%p, %s)", this, handle, message.utf8().data());
384     // This function is called when the browser is required to fail the
385     // WebSocketConnection. Hence we fail this channel by calling
386     // |this->failAsError| function.
387     failAsError(message);
388     // |this| may be deleted.
389 }
390
391 void NewWebSocketChannelImpl::didReceiveData(WebSocketHandle* handle, bool fin, WebSocketHandle::MessageType type, const char* data, size_t size)
392 {
393     WTF_LOG(Network, "NewWebSocketChannelImpl %p didReceiveData(%p, %d, %d, (%p, %zu))", this, handle, fin, type, data, size);
394     ASSERT(m_handle);
395     ASSERT(handle == m_handle);
396     ASSERT(m_client);
397     // Non-final frames cannot be empty.
398     ASSERT(fin || size);
399     switch (type) {
400     case WebSocketHandle::MessageTypeText:
401         ASSERT(m_receivingMessageData.isEmpty());
402         m_receivingMessageTypeIsText = true;
403         break;
404     case WebSocketHandle::MessageTypeBinary:
405         ASSERT(m_receivingMessageData.isEmpty());
406         m_receivingMessageTypeIsText = false;
407         break;
408     case WebSocketHandle::MessageTypeContinuation:
409         ASSERT(!m_receivingMessageData.isEmpty());
410         break;
411     }
412
413     m_receivingMessageData.append(data, size);
414     m_receivedDataSizeForFlowControl += size;
415     flowControlIfNecessary();
416     if (!fin) {
417         return;
418     }
419     if (m_identifier) {
420         // FIXME: Change the inspector API to show the entire message instead
421         // of individual frames.
422         WebSocketFrame::OpCode opcode = m_receivingMessageTypeIsText ? WebSocketFrame::OpCodeText : WebSocketFrame::OpCodeBinary;
423         WebSocketFrame frame(opcode, m_receivingMessageData.data(), m_receivingMessageData.size(), WebSocketFrame::Final);
424         InspectorInstrumentation::didReceiveWebSocketFrame(document(), m_identifier, frame.opCode, frame.masked, frame.payload, frame.payloadLength);
425     }
426     if (m_receivingMessageTypeIsText) {
427         String message = m_receivingMessageData.isEmpty() ? emptyString() : String::fromUTF8(m_receivingMessageData.data(), m_receivingMessageData.size());
428         m_receivingMessageData.clear();
429         if (message.isNull()) {
430             failAsError("Could not decode a text frame as UTF-8.");
431             // failAsError may delete this object.
432         } else {
433             m_client->didReceiveMessage(message);
434         }
435     } else {
436         OwnPtr<Vector<char> > binaryData = adoptPtr(new Vector<char>);
437         binaryData->swap(m_receivingMessageData);
438         m_client->didReceiveBinaryData(binaryData.release());
439     }
440 }
441
442 void NewWebSocketChannelImpl::didClose(WebSocketHandle* handle, bool wasClean, unsigned short code, const blink::WebString& reason)
443 {
444     WTF_LOG(Network, "NewWebSocketChannelImpl %p didClose(%p, %d, %u, %s)", this, handle, wasClean, code, String(reason).utf8().data());
445     ASSERT(m_handle);
446     m_handle.clear();
447     if (m_identifier) {
448         InspectorInstrumentation::didCloseWebSocket(document(), m_identifier);
449         m_identifier = 0;
450     }
451
452     handleDidClose(wasClean, code, reason);
453     // handleDidClose may delete this object.
454 }
455
456 void NewWebSocketChannelImpl::didReceiveFlowControl(WebSocketHandle* handle, int64_t quota)
457 {
458     WTF_LOG(Network, "NewWebSocketChannelImpl %p didReceiveFlowControl(%p, %ld)", this, handle, static_cast<long>(quota));
459     ASSERT(m_handle);
460     m_sendingQuota += quota;
461     sendInternal();
462 }
463
464 void NewWebSocketChannelImpl::didStartClosingHandshake(WebSocketHandle* handle)
465 {
466     WTF_LOG(Network, "NewWebSocketChannelImpl %p didStartClosingHandshake(%p)", this, handle);
467     if (m_client)
468         m_client->didStartClosingHandshake();
469 }
470
471 void NewWebSocketChannelImpl::didFinishLoadingBlob(PassRefPtr<ArrayBuffer> buffer)
472 {
473     m_blobLoader.clear();
474     ASSERT(m_handle);
475     // The loaded blob is always placed on m_messages[0].
476     ASSERT(m_messages.size() > 0 && m_messages.first().type == MessageTypeBlob);
477     // We replace it with the loaded blob.
478     m_messages.first() = Message(buffer);
479     sendInternal();
480 }
481
482 void NewWebSocketChannelImpl::didFailLoadingBlob(FileError::ErrorCode errorCode)
483 {
484     m_blobLoader.clear();
485     if (errorCode == FileError::ABORT_ERR) {
486         // The error is caused by cancel().
487         return;
488     }
489     // FIXME: Generate human-friendly reason message.
490     failAsError("Failed to load Blob: error code = " + String::number(errorCode));
491     // |this| can be deleted here.
492 }
493
494 } // namespace WebCore