2 * Copyright (C) 2009 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
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
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.
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.
33 #if ENABLE(WEB_SOCKETS)
35 #include "WebSocket.h"
38 #include "DOMWindow.h"
40 #include "EventException.h"
41 #include "EventListener.h"
42 #include "EventNames.h"
44 #include "MessageEvent.h"
45 #include "ScriptExecutionContext.h"
46 #include "WebSocketChannel.h"
47 #include <wtf/StdLibExtras.h>
51 class ProcessWebSocketEventTask : public ScriptExecutionContext::Task {
53 typedef void (WebSocket::*Method)(Event*);
54 static PassOwnPtr<ProcessWebSocketEventTask> create(PassRefPtr<WebSocket> webSocket, PassRefPtr<Event> event)
56 return new ProcessWebSocketEventTask(webSocket, event);
58 virtual void performTask(ScriptExecutionContext*)
61 m_webSocket->dispatchEvent(m_event.get(), ec);
66 ProcessWebSocketEventTask(PassRefPtr<WebSocket> webSocket, PassRefPtr<Event> event)
67 : m_webSocket(webSocket)
70 RefPtr<WebSocket> m_webSocket;
71 RefPtr<Event> m_event;
74 static bool isValidProtocolString(const WebCore::String& protocol)
76 if (protocol.isNull())
78 if (protocol.isEmpty())
80 const UChar* characters = protocol.characters();
81 for (size_t i = 0; i < protocol.length(); i++) {
82 if (characters[i] < 0x21 || characters[i] > 0x7E)
90 static bool webSocketsAvailable = false;
92 void WebSocket::setIsAvailable(bool available)
94 webSocketsAvailable = available;
97 bool WebSocket::isAvailable()
99 return webSocketsAvailable;
104 WebSocket::WebSocket(ScriptExecutionContext* context)
105 : ActiveDOMObject(context, this)
106 , m_state(CONNECTING)
110 WebSocket::~WebSocket()
113 m_channel->disconnect();
116 void WebSocket::connect(const KURL& url, ExceptionCode& ec)
118 connect(url, String(), ec);
121 void WebSocket::connect(const KURL& url, const String& protocol, ExceptionCode& ec)
123 LOG(Network, "WebSocket %p connect to %s protocol=%s", this, url.string().utf8().data(), protocol.utf8().data());
125 m_protocol = protocol;
127 if (!m_url.protocolIs("ws") && !m_url.protocolIs("wss")) {
128 LOG(Network, "Wrong url scheme for WebSocket %s", url.string().utf8().data());
133 if (!isValidProtocolString(m_protocol)) {
134 LOG(Network, "Wrong protocol for WebSocket %s", m_protocol.utf8().data());
139 if (!portAllowed(url)) {
140 LOG(Network, "WebSocket port %d blocked", url.port());
146 m_channel = WebSocketChannel::create(scriptExecutionContext(), this, m_url, m_protocol);
147 m_channel->connect();
150 bool WebSocket::send(const String& message, ExceptionCode& ec)
152 LOG(Network, "WebSocket %p send %s", this, message.utf8().data());
153 if (m_state == CONNECTING) {
154 ec = INVALID_STATE_ERR;
157 // No exception is raised if the connection was once established but has subsequently been closed.
158 if (m_state == CLOSED)
160 // FIXME: check message is valid utf8.
161 return m_channel->send(message);
164 void WebSocket::close()
166 LOG(Network, "WebSocket %p close", this);
167 if (m_state == CLOSED)
173 const KURL& WebSocket::url() const
178 WebSocket::State WebSocket::readyState() const
183 unsigned long WebSocket::bufferedAmount() const
186 return m_channel->bufferedAmount();
190 ScriptExecutionContext* WebSocket::scriptExecutionContext() const
192 return ActiveDOMObject::scriptExecutionContext();
195 void WebSocket::didConnect()
197 LOG(Network, "WebSocket %p didConnect", this);
198 if (m_state != CONNECTING || !scriptExecutionContext()) {
203 scriptExecutionContext()->postTask(ProcessWebSocketEventTask::create(this, Event::create(eventNames().openEvent, false, false)));
206 void WebSocket::didReceiveMessage(const String& msg)
208 LOG(Network, "WebSocket %p didReceiveMessage %s", this, msg.utf8().data());
209 if (m_state != OPEN || !scriptExecutionContext())
211 RefPtr<MessageEvent> evt = MessageEvent::create();
212 // FIXME: origin, lastEventId, source, messagePort.
213 evt->initMessageEvent(eventNames().messageEvent, false, false, SerializedScriptValue::create(msg), "", "", 0, 0);
214 scriptExecutionContext()->postTask(ProcessWebSocketEventTask::create(this, evt));
217 void WebSocket::didClose()
219 LOG(Network, "WebSocket %p didClose", this);
221 if (scriptExecutionContext())
222 scriptExecutionContext()->postTask(ProcessWebSocketEventTask::create(this, Event::create(eventNames().closeEvent, false, false)));
225 EventTargetData* WebSocket::eventTargetData()
227 return &m_eventTargetData;
230 EventTargetData* WebSocket::ensureEventTargetData()
232 return &m_eventTargetData;
235 } // namespace WebCore