1 /* 2 * Copyright (C) 2011 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 #ifndef WebSocket_h 32 #define WebSocket_h 33 34 #include "bindings/v8/ScriptWrappable.h" 35 #include "core/dom/ActiveDOMObject.h" 36 #include "core/events/EventListener.h" 37 #include "modules/EventTargetModules.h" 38 #include "modules/websockets/WebSocketChannel.h" 39 #include "modules/websockets/WebSocketChannelClient.h" 40 #include "platform/Timer.h" 41 #include "platform/heap/Handle.h" 42 #include "platform/weborigin/KURL.h" 43 #include "wtf/Deque.h" 44 #include "wtf/Forward.h" 45 #include "wtf/OwnPtr.h" 46 #include "wtf/RefCounted.h" 47 #include "wtf/text/AtomicStringHash.h" 48 49 namespace WebCore { 50 51 class Blob; 52 class ExceptionState; 53 54 class WebSocket : public RefCountedWillBeRefCountedGarbageCollected<WebSocket>, public ScriptWrappable, public EventTargetWithInlineData, public ActiveDOMObject, public WebSocketChannelClient { 55 REFCOUNTED_EVENT_TARGET(WebSocket); 56 WILL_BE_USING_GARBAGE_COLLECTED_MIXIN(WebSocket); 57 public: 58 static const char* subprotocolSeperator(); 59 // WebSocket instances must be used with a wrapper since this class's 60 // lifetime management is designed assuming the V8 holds a ref on it while 61 // hasPendingActivity() returns true. 62 static PassRefPtrWillBeRawPtr<WebSocket> create(ExecutionContext*, const String& url, ExceptionState&); 63 static PassRefPtrWillBeRawPtr<WebSocket> create(ExecutionContext*, const String& url, const String& protocol, ExceptionState&); 64 static PassRefPtrWillBeRawPtr<WebSocket> create(ExecutionContext*, const String& url, const Vector<String>& protocols, ExceptionState&); 65 virtual ~WebSocket(); 66 67 enum State { 68 CONNECTING = 0, 69 OPEN = 1, 70 CLOSING = 2, 71 CLOSED = 3 72 }; 73 74 void connect(const String& url, const Vector<String>& protocols, ExceptionState&); 75 76 void send(const String& message, ExceptionState&); 77 void send(ArrayBuffer*, ExceptionState&); 78 void send(ArrayBufferView*, ExceptionState&); 79 void send(Blob*, ExceptionState&); 80 81 // To distinguish close method call with the code parameter from one 82 // without, we have these three signatures. Use of 83 // Optional=DefaultIsUndefined in the IDL file doesn't help for now since 84 // it's bound to a value of 0 which is indistinguishable from the case 0 85 // is passed as code parameter. 86 void close(unsigned short code, const String& reason, ExceptionState&); 87 void close(ExceptionState&); 88 void close(unsigned short code, ExceptionState&); 89 90 const KURL& url() const; 91 State readyState() const; 92 unsigned long bufferedAmount() const; 93 94 String protocol() const; 95 String extensions() const; 96 97 String binaryType() const; 98 void setBinaryType(const String&); 99 100 DEFINE_ATTRIBUTE_EVENT_LISTENER(open); 101 DEFINE_ATTRIBUTE_EVENT_LISTENER(message); 102 DEFINE_ATTRIBUTE_EVENT_LISTENER(error); 103 DEFINE_ATTRIBUTE_EVENT_LISTENER(close); 104 105 // EventTarget functions. 106 virtual const AtomicString& interfaceName() const OVERRIDE; 107 virtual ExecutionContext* executionContext() const OVERRIDE; 108 109 // ActiveDOMObject functions. 110 virtual void contextDestroyed() OVERRIDE; 111 // Prevent this instance from being collected while it's not in CLOSED 112 // state. 113 virtual bool hasPendingActivity() const OVERRIDE; 114 virtual void suspend() OVERRIDE; 115 virtual void resume() OVERRIDE; 116 virtual void stop() OVERRIDE; 117 118 // WebSocketChannelClient functions. 119 virtual void didConnect(const String& subprotocol, const String& extensions) OVERRIDE; 120 virtual void didReceiveMessage(const String& message) OVERRIDE; 121 virtual void didReceiveBinaryData(PassOwnPtr<Vector<char> >) OVERRIDE; 122 virtual void didReceiveMessageError() OVERRIDE; 123 virtual void didConsumeBufferedAmount(unsigned long) OVERRIDE; 124 virtual void didStartClosingHandshake() OVERRIDE; 125 virtual void didClose(ClosingHandshakeCompletionStatus, unsigned short code, const String& reason) OVERRIDE; 126 127 virtual void trace(Visitor*) OVERRIDE; 128 129 static bool isValidSubprotocolString(const String&); 130 131 protected: 132 explicit WebSocket(ExecutionContext*); 133 134 private: 135 // FIXME: This should inherit WebCore::EventQueue. 136 class EventQueue FINAL : public RefCountedWillBeGarbageCollectedFinalized<EventQueue> { 137 public: create(EventTarget * target)138 static PassRefPtrWillBeRawPtr<EventQueue> create(EventTarget* target) 139 { 140 return adoptRefWillBeNoop(new EventQueue(target)); 141 } 142 ~EventQueue(); 143 144 // Dispatches the event if this queue is active. 145 // Queues the event if this queue is suspended. 146 // Does nothing otherwise. 147 void dispatch(PassRefPtrWillBeRawPtr<Event> /* event */); 148 149 bool isEmpty() const; 150 151 void suspend(); 152 void resume(); 153 void stop(); 154 155 void trace(Visitor*); 156 157 private: 158 enum State { 159 Active, 160 Suspended, 161 Stopped, 162 }; 163 164 explicit EventQueue(EventTarget*); 165 166 // Dispatches queued events if this queue is active. 167 // Does nothing otherwise. 168 void dispatchQueuedEvents(); 169 void resumeTimerFired(Timer<EventQueue>*); 170 171 State m_state; 172 EventTarget* m_target; 173 WillBeHeapDeque<RefPtrWillBeMember<Event> > m_events; 174 Timer<EventQueue> m_resumeTimer; 175 }; 176 177 enum WebSocketSendType { 178 WebSocketSendTypeString, 179 WebSocketSendTypeArrayBuffer, 180 WebSocketSendTypeArrayBufferView, 181 WebSocketSendTypeBlob, 182 WebSocketSendTypeMax, 183 }; 184 185 // This function is virtual for unittests. 186 // FIXME: Move WebSocketChannel::create here. createChannel(ExecutionContext * context,WebSocketChannelClient * client)187 virtual PassRefPtrWillBeRawPtr<WebSocketChannel> createChannel(ExecutionContext* context, WebSocketChannelClient* client) 188 { 189 return WebSocketChannel::create(context, client); 190 } 191 192 // Adds a console message with JSMessageSource and ErrorMessageLevel. 193 void logError(const String& message); 194 195 // Handle the JavaScript close method call. close() methods on this class 196 // are just for determining if the optional code argument is supplied or 197 // not. 198 void closeInternal(int, const String&, ExceptionState&); 199 200 size_t getFramingOverhead(size_t payloadSize); 201 202 // Checks the result of WebSocketChannel::send() method, and: 203 // - shows console message 204 // - sets ExceptionState appropriately 205 // - reports data for UMA. 206 void handleSendResult(WebSocketChannel::SendResult, ExceptionState&, WebSocketSendType); 207 208 // Updates m_bufferedAmountAfterClose given the amount of data passed to 209 // send() method after the state changed to CLOSING or CLOSED. 210 void updateBufferedAmountAfterClose(unsigned long); 211 void reflectBufferedAmountConsumption(Timer<WebSocket>*); 212 213 void releaseChannel(); 214 215 enum BinaryType { 216 BinaryTypeBlob, 217 BinaryTypeArrayBuffer 218 }; 219 220 RefPtrWillBeMember<WebSocketChannel> m_channel; 221 222 State m_state; 223 KURL m_url; 224 unsigned long m_bufferedAmount; 225 // The consumed buffered amount that will be reflected to m_bufferedAmount 226 // later. It will be cleared once reflected. 227 unsigned long m_consumedBufferedAmount; 228 unsigned long m_bufferedAmountAfterClose; 229 BinaryType m_binaryType; 230 // The subprotocol the server selected. 231 String m_subprotocol; 232 String m_extensions; 233 234 RefPtrWillBeMember<EventQueue> m_eventQueue; 235 Timer<WebSocket> m_bufferedAmountConsumeTimer; 236 }; 237 238 } // namespace WebCore 239 240 #endif // WebSocket_h 241