1/*
2 * Copyright (C) 2011, 2012 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 "web/WebSocketImpl.h"
33
34#include "core/dom/Document.h"
35#include "core/frame/ConsoleTypes.h"
36#include "modules/websockets/MainThreadWebSocketChannel.h"
37#include "modules/websockets/NewWebSocketChannelImpl.h"
38#include "modules/websockets/WebSocketChannel.h"
39#include "platform/RuntimeEnabledFeatures.h"
40#include "public/platform/WebArrayBuffer.h"
41#include "public/platform/WebString.h"
42#include "public/platform/WebURL.h"
43#include "public/web/WebDocument.h"
44#include "web/WebSocketChannelClientProxy.h"
45#include "wtf/ArrayBuffer.h"
46#include "wtf/text/CString.h"
47#include "wtf/text/WTFString.h"
48
49namespace blink {
50
51WebSocketImpl::WebSocketImpl(const WebDocument& document, WebSocketClient* client)
52    : m_client(client)
53    , m_channelProxy(WebSocketChannelClientProxy::create(this))
54    , m_binaryType(BinaryTypeBlob)
55    , m_isClosingOrClosed(false)
56    , m_bufferedAmount(0)
57    , m_bufferedAmountAfterClose(0)
58{
59    RefPtrWillBeRawPtr<Document> coreDocument = PassRefPtrWillBeRawPtr<Document>(document);
60    if (RuntimeEnabledFeatures::experimentalWebSocketEnabled()) {
61        m_private = NewWebSocketChannelImpl::create(coreDocument.get(), m_channelProxy.get());
62    } else {
63        m_private = MainThreadWebSocketChannel::create(coreDocument.get(), m_channelProxy.get());
64    }
65}
66
67WebSocketImpl::~WebSocketImpl()
68{
69    m_private->disconnect();
70}
71
72WebSocket::BinaryType WebSocketImpl::binaryType() const
73{
74    return m_binaryType;
75}
76
77bool WebSocketImpl::setBinaryType(BinaryType binaryType)
78{
79    if (binaryType > BinaryTypeArrayBuffer)
80        return false;
81    m_binaryType = binaryType;
82    return true;
83}
84
85void WebSocketImpl::connect(const WebURL& url, const WebString& protocol)
86{
87    m_private->connect(url, protocol);
88}
89
90WebString WebSocketImpl::subprotocol()
91{
92    return m_subprotocol;
93}
94
95WebString WebSocketImpl::extensions()
96{
97    return m_extensions;
98}
99
100bool WebSocketImpl::sendText(const WebString& message)
101{
102    size_t size = message.utf8().length();
103    m_bufferedAmount += size;
104    if (m_isClosingOrClosed)
105        m_bufferedAmountAfterClose += size;
106
107    // FIXME: Deprecate this call.
108    m_client->didUpdateBufferedAmount(m_bufferedAmount);
109
110    if (m_isClosingOrClosed)
111        return true;
112
113    m_private->send(message);
114    return true;
115}
116
117bool WebSocketImpl::sendArrayBuffer(const WebArrayBuffer& webArrayBuffer)
118{
119    size_t size = webArrayBuffer.byteLength();
120    m_bufferedAmount += size;
121    if (m_isClosingOrClosed)
122        m_bufferedAmountAfterClose += size;
123
124    // FIXME: Deprecate this call.
125    m_client->didUpdateBufferedAmount(m_bufferedAmount);
126
127    if (m_isClosingOrClosed)
128        return true;
129
130    m_private->send(*PassRefPtr<ArrayBuffer>(webArrayBuffer), 0, webArrayBuffer.byteLength());
131    return true;
132}
133
134unsigned long WebSocketImpl::bufferedAmount() const
135{
136    return m_bufferedAmount;
137}
138
139void WebSocketImpl::close(int code, const WebString& reason)
140{
141    m_isClosingOrClosed = true;
142    m_private->close(code, reason);
143}
144
145void WebSocketImpl::fail(const WebString& reason)
146{
147    m_private->fail(reason, ErrorMessageLevel, String(), 0);
148}
149
150void WebSocketImpl::disconnect()
151{
152    m_private->disconnect();
153    m_client = 0;
154}
155
156void WebSocketImpl::didConnect(const String& subprotocol, const String& extensions)
157{
158    m_client->didConnect(subprotocol, extensions);
159
160    // FIXME: Deprecate these statements.
161    m_subprotocol = subprotocol;
162    m_extensions = extensions;
163    m_client->didConnect();
164}
165
166void WebSocketImpl::didReceiveMessage(const String& message)
167{
168    m_client->didReceiveMessage(WebString(message));
169}
170
171void WebSocketImpl::didReceiveBinaryData(PassOwnPtr<Vector<char> > binaryData)
172{
173    switch (m_binaryType) {
174    case BinaryTypeBlob:
175        // FIXME: Handle Blob after supporting WebBlob.
176        break;
177    case BinaryTypeArrayBuffer:
178        m_client->didReceiveArrayBuffer(WebArrayBuffer(ArrayBuffer::create(binaryData->data(), binaryData->size())));
179        break;
180    }
181}
182
183void WebSocketImpl::didReceiveMessageError()
184{
185    m_client->didReceiveMessageError();
186}
187
188void WebSocketImpl::didConsumeBufferedAmount(unsigned long consumed)
189{
190    m_client->didConsumeBufferedAmount(consumed);
191
192    // FIXME: Deprecate the following statements.
193    m_bufferedAmount -= consumed;
194    m_client->didUpdateBufferedAmount(m_bufferedAmount);
195}
196
197void WebSocketImpl::didStartClosingHandshake()
198{
199    m_client->didStartClosingHandshake();
200}
201
202void WebSocketImpl::didClose(WebSocketChannelClient::ClosingHandshakeCompletionStatus status, unsigned short code, const String& reason)
203{
204    m_isClosingOrClosed = true;
205    m_client->didClose(static_cast<WebSocketClient::ClosingHandshakeCompletionStatus>(status), code, WebString(reason));
206
207    // FIXME: Deprecate this call.
208    m_client->didClose(m_bufferedAmount - m_bufferedAmountAfterClose, static_cast<WebSocketClient::ClosingHandshakeCompletionStatus>(status), code, WebString(reason));
209}
210
211} // namespace blink
212