Home | History | Annotate | Download | only in websockets
      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 "core/events/EventTarget.h"
     38 #include "core/events/ThreadLocalEventNames.h"
     39 #include "modules/websockets/WebSocketChannel.h"
     40 #include "modules/websockets/WebSocketChannelClient.h"
     41 #include "platform/Timer.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 RefCounted<WebSocket>, public ScriptWrappable, public EventTargetWithInlineData, public ActiveDOMObject, public WebSocketChannelClient {
     55     REFCOUNTED_EVENT_TARGET(WebSocket);
     56 public:
     57     static const char* subProtocolSeperator();
     58     // WebSocket instances must be used with a wrapper since this class's
     59     // lifetime management is designed assuming the V8 holds a ref on it while
     60     // hasPendingActivity() returns true.
     61     static PassRefPtr<WebSocket> create(ExecutionContext*, const String& url, ExceptionState&);
     62     static PassRefPtr<WebSocket> create(ExecutionContext*, const String& url, const String& protocol, ExceptionState&);
     63     static PassRefPtr<WebSocket> create(ExecutionContext*, const String& url, const Vector<String>& protocols, ExceptionState&);
     64     virtual ~WebSocket();
     65 
     66     enum State {
     67         CONNECTING = 0,
     68         OPEN = 1,
     69         CLOSING = 2,
     70         CLOSED = 3
     71     };
     72 
     73     void connect(const String& url, ExceptionState&);
     74     void connect(const String& url, const String& protocol, ExceptionState&);
     75     void connect(const String& url, const Vector<String>& protocols, ExceptionState&);
     76 
     77     void send(const String& message, ExceptionState&);
     78     void send(ArrayBuffer*, ExceptionState&);
     79     void send(ArrayBufferView*, ExceptionState&);
     80     void send(Blob*, ExceptionState&);
     81 
     82     // To distinguish close method call with the code parameter from one
     83     // without, we have these three signatures. Use of
     84     // Optional=DefaultIsUndefined in the IDL file doesn't help for now since
     85     // it's bound to a value of 0 which is indistinguishable from the case 0
     86     // is passed as code parameter.
     87     void close(unsigned short code, const String& reason, ExceptionState&);
     88     void close(ExceptionState&);
     89     void close(unsigned short code, ExceptionState&);
     90 
     91     const KURL& url() const;
     92     State readyState() const;
     93     unsigned long bufferedAmount() const;
     94 
     95     String protocol() const;
     96     String extensions() const;
     97 
     98     String binaryType() const;
     99     void setBinaryType(const String&);
    100 
    101     DEFINE_ATTRIBUTE_EVENT_LISTENER(open);
    102     DEFINE_ATTRIBUTE_EVENT_LISTENER(message);
    103     DEFINE_ATTRIBUTE_EVENT_LISTENER(error);
    104     DEFINE_ATTRIBUTE_EVENT_LISTENER(close);
    105 
    106     // EventTarget functions.
    107     virtual const AtomicString& interfaceName() const OVERRIDE;
    108     virtual ExecutionContext* executionContext() const OVERRIDE;
    109 
    110     // ActiveDOMObject functions.
    111     virtual void contextDestroyed() OVERRIDE;
    112     // Prevent this instance from being collected while it's not in CLOSED
    113     // state.
    114     virtual bool hasPendingActivity() const OVERRIDE;
    115     virtual void suspend() OVERRIDE;
    116     virtual void resume() OVERRIDE;
    117     virtual void stop() OVERRIDE;
    118 
    119     // WebSocketChannelClient functions.
    120     virtual void didConnect() OVERRIDE;
    121     virtual void didReceiveMessage(const String& message) OVERRIDE;
    122     virtual void didReceiveBinaryData(PassOwnPtr<Vector<char> >) OVERRIDE;
    123     virtual void didReceiveMessageError() OVERRIDE;
    124     virtual void didUpdateBufferedAmount(unsigned long bufferedAmount) OVERRIDE;
    125     virtual void didStartClosingHandshake() OVERRIDE;
    126     virtual void didClose(unsigned long unhandledBufferedAmount, ClosingHandshakeCompletionStatus, unsigned short code, const String& reason) OVERRIDE;
    127 
    128 private:
    129     class EventQueue : public RefCounted<EventQueue> {
    130     public:
    131         static PassRefPtr<EventQueue> create(EventTarget* target) { return adoptRef(new EventQueue(target)); }
    132         virtual ~EventQueue();
    133 
    134         // Dispatches the event if this queue is active.
    135         // Queues the event if this queue is suspended.
    136         // Does nothing otherwise.
    137         void dispatch(PassRefPtr<Event> /* event */);
    138 
    139         void suspend();
    140         void resume();
    141         void stop();
    142 
    143     private:
    144         enum State {
    145             Active,
    146             Suspended,
    147             Stopped,
    148         };
    149 
    150         explicit EventQueue(EventTarget*);
    151 
    152         // Dispatches queued events if this queue is active.
    153         // Does nothing otherwise.
    154         void dispatchQueuedEvents();
    155         void resumeTimerFired(Timer<EventQueue>*);
    156 
    157         State m_state;
    158         EventTarget* m_target;
    159         Deque<RefPtr<Event> > m_events;
    160         Timer<EventQueue> m_resumeTimer;
    161     };
    162 
    163     explicit WebSocket(ExecutionContext*);
    164 
    165     // Adds a console message with JSMessageSource and ErrorMessageLevel.
    166     void logError(const String& message);
    167 
    168     // Handle the JavaScript close method call. close() methods on this class
    169     // are just for determining if the optional code argument is supplied or
    170     // not.
    171     void closeInternal(int, const String&, ExceptionState&);
    172 
    173     size_t getFramingOverhead(size_t payloadSize);
    174 
    175     // Checks the result of WebSocketChannel::send() method, and shows console
    176     // message and sets ec appropriately.
    177     void handleSendResult(WebSocketChannel::SendResult, ExceptionState&);
    178 
    179     // Updates m_bufferedAmountAfterClose given the amount of data passed to
    180     // send() method after the state changed to CLOSING or CLOSED.
    181     void updateBufferedAmountAfterClose(unsigned long);
    182 
    183     enum BinaryType {
    184         BinaryTypeBlob,
    185         BinaryTypeArrayBuffer
    186     };
    187 
    188     RefPtr<WebSocketChannel> m_channel;
    189 
    190     State m_state;
    191     KURL m_url;
    192     unsigned long m_bufferedAmount;
    193     unsigned long m_bufferedAmountAfterClose;
    194     BinaryType m_binaryType;
    195     String m_subprotocol;
    196     String m_extensions;
    197 
    198     RefPtr<EventQueue> m_eventQueue;
    199 };
    200 
    201 } // namespace WebCore
    202 
    203 #endif // WebSocket_h
    204