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