michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set sw=2 ts=8 et tw=80 : */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef WebSocket_h__ michael@0: #define WebSocket_h__ michael@0: michael@0: #include "mozilla/Attributes.h" michael@0: #include "mozilla/dom/TypedArray.h" michael@0: #include "mozilla/dom/WebSocketBinding.h" // for BinaryType michael@0: #include "mozilla/DOMEventTargetHelper.h" michael@0: #include "mozilla/ErrorResult.h" michael@0: #include "nsAutoPtr.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsCycleCollectionParticipant.h" michael@0: #include "nsIInterfaceRequestor.h" michael@0: #include "nsIObserver.h" michael@0: #include "nsIRequest.h" michael@0: #include "nsISupports.h" michael@0: #include "nsISupportsUtils.h" michael@0: #include "nsIWebSocketChannel.h" michael@0: #include "nsIWebSocketListener.h" michael@0: #include "nsString.h" michael@0: #include "nsWeakReference.h" michael@0: #include "nsWrapperCache.h" michael@0: michael@0: #define DEFAULT_WS_SCHEME_PORT 80 michael@0: #define DEFAULT_WSS_SCHEME_PORT 443 michael@0: michael@0: namespace mozilla { michael@0: namespace dom { michael@0: michael@0: class WebSocket : public DOMEventTargetHelper, michael@0: public nsIInterfaceRequestor, michael@0: public nsIWebSocketListener, michael@0: public nsIObserver, michael@0: public nsSupportsWeakReference, michael@0: public nsIRequest michael@0: { michael@0: friend class CallDispatchConnectionCloseEvents; michael@0: friend class nsAutoCloseWS; michael@0: michael@0: public: michael@0: enum { michael@0: CONNECTING = 0, michael@0: OPEN = 1, michael@0: CLOSING = 2, michael@0: CLOSED = 3 michael@0: }; michael@0: michael@0: public: michael@0: NS_DECL_ISUPPORTS_INHERITED michael@0: NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS_INHERITED( michael@0: WebSocket, DOMEventTargetHelper) michael@0: NS_DECL_NSIINTERFACEREQUESTOR michael@0: NS_DECL_NSIWEBSOCKETLISTENER michael@0: NS_DECL_NSIOBSERVER michael@0: NS_DECL_NSIREQUEST michael@0: michael@0: // EventTarget michael@0: virtual void EventListenerAdded(nsIAtom* aType) MOZ_OVERRIDE; michael@0: virtual void EventListenerRemoved(nsIAtom* aType) MOZ_OVERRIDE; michael@0: michael@0: virtual void DisconnectFromOwner() MOZ_OVERRIDE; michael@0: michael@0: // nsWrapperCache michael@0: nsPIDOMWindow* GetParentObject() { return GetOwner(); } michael@0: michael@0: virtual JSObject* WrapObject(JSContext *cx) MOZ_OVERRIDE; michael@0: michael@0: public: // static helpers: michael@0: michael@0: // Determine if preferences allow WebSocket michael@0: static bool PrefEnabled(JSContext* aCx = nullptr, JSObject* aGlobal = nullptr); michael@0: michael@0: public: // WebIDL interface: michael@0: michael@0: // Constructor: michael@0: static already_AddRefed Constructor(const GlobalObject& aGlobal, michael@0: const nsAString& aUrl, michael@0: ErrorResult& rv); michael@0: michael@0: static already_AddRefed Constructor(const GlobalObject& aGlobal, michael@0: const nsAString& aUrl, michael@0: const nsAString& aProtocol, michael@0: ErrorResult& rv); michael@0: michael@0: static already_AddRefed Constructor(const GlobalObject& aGlobal, michael@0: const nsAString& aUrl, michael@0: const Sequence& aProtocols, michael@0: ErrorResult& rv); michael@0: michael@0: // webIDL: readonly attribute DOMString url michael@0: void GetUrl(nsAString& aResult); michael@0: michael@0: // webIDL: readonly attribute unsigned short readyState; michael@0: uint16_t ReadyState() const { return mReadyState; } michael@0: michael@0: // webIDL: readonly attribute unsigned long bufferedAmount; michael@0: uint32_t BufferedAmount() const { return mOutgoingBufferedAmount; } michael@0: michael@0: // webIDL: attribute Function? onopen; michael@0: IMPL_EVENT_HANDLER(open) michael@0: michael@0: // webIDL: attribute Function? onerror; michael@0: IMPL_EVENT_HANDLER(error) michael@0: michael@0: // webIDL: attribute Function? onclose; michael@0: IMPL_EVENT_HANDLER(close) michael@0: michael@0: // webIDL: readonly attribute DOMString extensions; michael@0: void GetExtensions(nsAString& aResult); michael@0: michael@0: // webIDL: readonly attribute DOMString protocol; michael@0: void GetProtocol(nsAString& aResult); michael@0: michael@0: // webIDL: void close(optional unsigned short code, optional DOMString reason): michael@0: void Close(const Optional& aCode, michael@0: const Optional& aReason, michael@0: ErrorResult& aRv); michael@0: michael@0: // webIDL: attribute Function? onmessage; michael@0: IMPL_EVENT_HANDLER(message) michael@0: michael@0: // webIDL: attribute DOMString binaryType; michael@0: dom::BinaryType BinaryType() const { return mBinaryType; } michael@0: void SetBinaryType(dom::BinaryType aData) { mBinaryType = aData; } michael@0: michael@0: // webIDL: void send(DOMString|Blob|ArrayBufferView data); michael@0: void Send(const nsAString& aData, michael@0: ErrorResult& aRv); michael@0: void Send(nsIDOMBlob* aData, michael@0: ErrorResult& aRv); michael@0: void Send(const ArrayBuffer& aData, michael@0: ErrorResult& aRv); michael@0: void Send(const ArrayBufferView& aData, michael@0: ErrorResult& aRv); michael@0: michael@0: private: // constructor && distructor michael@0: WebSocket(nsPIDOMWindow* aOwnerWindow); michael@0: virtual ~WebSocket(); michael@0: michael@0: protected: michael@0: nsresult Init(JSContext* aCx, michael@0: nsIPrincipal* aPrincipal, michael@0: const nsAString& aURL, michael@0: nsTArray& aProtocolArray); michael@0: michael@0: void Send(nsIInputStream* aMsgStream, michael@0: const nsACString& aMsgString, michael@0: uint32_t aMsgLength, michael@0: bool aIsBinary, michael@0: ErrorResult& aRv); michael@0: michael@0: nsresult ParseURL(const nsString& aURL); michael@0: nsresult EstablishConnection(); michael@0: michael@0: // These methods when called can release the WebSocket object michael@0: void FailConnection(uint16_t reasonCode, michael@0: const nsACString& aReasonString = EmptyCString()); michael@0: nsresult CloseConnection(uint16_t reasonCode, michael@0: const nsACString& aReasonString = EmptyCString()); michael@0: nsresult Disconnect(); michael@0: michael@0: nsresult ConsoleError(); michael@0: nsresult PrintErrorOnConsole(const char* aBundleURI, michael@0: const char16_t* aError, michael@0: const char16_t** aFormatStrings, michael@0: uint32_t aFormatStringsLen); michael@0: michael@0: nsresult DoOnMessageAvailable(const nsACString& aMsg, michael@0: bool isBinary); michael@0: michael@0: // ConnectionCloseEvents: 'error' event if needed, then 'close' event. michael@0: // - These must not be dispatched while we are still within an incoming call michael@0: // from JS (ex: close()). Set 'sync' to false in that case to dispatch in a michael@0: // separate new event. michael@0: nsresult ScheduleConnectionCloseEvents(nsISupports* aContext, michael@0: nsresult aStatusCode, michael@0: bool sync); michael@0: // 2nd half of ScheduleConnectionCloseEvents, sometimes run in its own event. michael@0: void DispatchConnectionCloseEvents(); michael@0: michael@0: // These methods actually do the dispatch for various events. michael@0: nsresult CreateAndDispatchSimpleEvent(const nsString& aName); michael@0: nsresult CreateAndDispatchMessageEvent(const nsACString& aData, michael@0: bool isBinary); michael@0: nsresult CreateAndDispatchCloseEvent(bool aWasClean, michael@0: uint16_t aCode, michael@0: const nsString& aReason); michael@0: michael@0: // if there are "strong event listeners" (see comment in WebSocket.cpp) or michael@0: // outgoing not sent messages then this method keeps the object alive michael@0: // when js doesn't have strong references to it. michael@0: void UpdateMustKeepAlive(); michael@0: // ATTENTION, when calling this method the object can be released michael@0: // (and possibly collected). michael@0: void DontKeepAliveAnyMore(); michael@0: michael@0: nsresult UpdateURI(); michael@0: michael@0: protected: //data michael@0: michael@0: nsCOMPtr mChannel; michael@0: michael@0: // related to the WebSocket constructor steps michael@0: nsString mOriginalURL; michael@0: nsString mEffectiveURL; // after redirects michael@0: bool mSecure; // if true it is using SSL and the wss scheme, michael@0: // otherwise it is using the ws scheme with no SSL michael@0: michael@0: bool mKeepingAlive; michael@0: bool mCheckMustKeepAlive; michael@0: bool mOnCloseScheduled; michael@0: bool mFailed; michael@0: bool mDisconnected; michael@0: michael@0: // Set attributes of DOM 'onclose' message michael@0: bool mCloseEventWasClean; michael@0: nsString mCloseEventReason; michael@0: uint16_t mCloseEventCode; michael@0: michael@0: nsCString mAsciiHost; // hostname michael@0: uint32_t mPort; michael@0: nsCString mResource; // [filepath[?query]] michael@0: nsString mUTF16Origin; michael@0: michael@0: nsCOMPtr mURI; michael@0: nsCString mRequestedProtocolList; michael@0: nsCString mEstablishedProtocol; michael@0: nsCString mEstablishedExtensions; michael@0: michael@0: uint16_t mReadyState; michael@0: michael@0: nsCOMPtr mPrincipal; michael@0: michael@0: uint32_t mOutgoingBufferedAmount; michael@0: michael@0: dom::BinaryType mBinaryType; michael@0: michael@0: // Web Socket owner information: michael@0: // - the script file name, UTF8 encoded. michael@0: // - source code line number where the Web Socket object was constructed. michael@0: // - the ID of the inner window where the script lives. Note that this may not michael@0: // be the same as the Web Socket owner window. michael@0: // These attributes are used for error reporting. michael@0: nsCString mScriptFile; michael@0: uint32_t mScriptLine; michael@0: uint64_t mInnerWindowID; michael@0: michael@0: private: michael@0: WebSocket(const WebSocket& x) MOZ_DELETE; // prevent bad usage michael@0: WebSocket& operator=(const WebSocket& x) MOZ_DELETE; michael@0: }; michael@0: michael@0: } //namespace dom michael@0: } //namespace mozilla michael@0: michael@0: #endif